sign a string in java and SHA256 - java

I am trying for days(!) to sign the following string with SHA256 with a secret key: "aaa" the result should be (URL endcoded) :
kvoJVZMPomuGyYP3cmiJkYz2L3usuZNfh2f9LaUxO3U%3D
Can anyone help please ?
GET
sellercentral.amazon.com
/gp/mws/registration/register.html
AWSAccessKeyId=AKIAFJPPO5KLY6G4XO7Q&SignatureMethod=HmacSHA256&SignatureVersion=2&id=1014f5ad-c359-4e86-8e50-bb8f8e431a9e&returnPathAndParameters=%2Forders%2FlistRecentOrders.jsp%3FsessionId%3D123
This is the code I am using but I can't get the same result:
private static final String QUERY = "GET\n"+
"sellercentral.amazon.com\n"+
"/gp/mws/registration/register.html\n"+
"AWSAccessKeyId=AKIAFJPPO5KLY6G4XO7Q&SignatureMethod=HmacSHA256&SignatureVersion=2&id=1014f5ad-c359-4e86-8e50-bb8f8e431a9e&returnPathAndParameters=%2Forders%2FlistRecentOrders.jsp%3FsessionId%3D123";
public static void main(String[] args) throws Exception {
System.out.println(encode("aaa", QUERY));
}
public static String encode(String key, String data) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
return Base64.encodeBase64String(sha256_HMAC.doFinal(data.getBytes()));
}

Just to help others if they get Amazon documentation for the IRP (integrated registration pipeline) - note that their example result for signing a query string is wrong.

Related

cert.verify() throws java.security.InvalidKeyException: Supplied key is not a RSAPublicKey instance

I'm trying to check whether a certificate is self-signed.
public static void main(String[] args) throws CertificateException, IOException, GeneralSecurityException
{
// InputStream is = new URL("http://www.d-trust.net/cgi-bin/D-TRUST_Root_CA_2_2021.crt").openStream(); // ok
InputStream is = new URL("http://www.d-trust.net/cgi-bin/D-TRUST_Root_CA_1_2017.crt").openStream(); // not ok
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(is);
System.out.println(cert);
System.out.println("Self signed? " + isSelfSigned(cert));
}
public static boolean isSelfSigned(X509Certificate cert) throws GeneralSecurityException
{
try
{
// Try to verify certificate signature with its own public key
PublicKey key = cert.getPublicKey();
System.out.println("key class: " + key.getClass().getName());
System.out.println("Algorithm: " + key.getAlgorithm());
cert.verify(key, new BouncyCastleProvider());
return true;
}
catch (SignatureException | InvalidKeyException ex)
{
// Invalid signature --> not self-signed
ex.printStackTrace();
return false;
}
}
I get this exception in isSelfSigned():
java.security.InvalidKeyException: Supplied key is not a RSAPublicKey instance
at org.bouncycastle.jcajce.provider.asymmetric.rsa.PSSSignatureSpi.engineInitVerify(Unknown Source)
at java.security.Signature$Delegate.engineInitVerify(Signature.java:1168)
at java.security.Signature.initVerify(Signature.java:460)
at sun.security.x509.X509CertImpl.verify(X509CertImpl.java:483)
at NewClass1.isSelfSigned(NewClass1.java:46)
at NewClass1.main(NewClass1.java:35)
This happens only with one of the URLs in my code, not the other one. The problematic certificate has algorithm 1.2.840.113549.1.1.10, which is RSASSA-PSS. I'm using BouncyCastle bcmail-jdk18on 1.72, which also uses bcprov-jdk18on and bcpkix-jdk18on as dependencies.
I'm assuming that this is a self-signed certificate, but of course I don't know for sure.
It turned out to be a java bug. I was using an older jdk8 version, and it runs fine on the current jdk8 version (Amazon Corretto 1.8.0_352). Thanks Topaco for your help.

InvalidKeySpecException when reading RSA private while building Spring bean

I am working with a legacy code base and encountering really puzzling behavior while instantiating RSAPrivateKey.
I have a RSA private key:
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
Based on the headers it looks like the RSA private key is in format PKCS#1.
I then have Spring config class as follows:
#Configuration
public class AppConfig {
// Gets the above RSA key from config file
#Value("${key}")
private String key;
#Bean
public String someRandomTestBean() {
try {
// builds the RSAPrivateKey without any errors even though key is in PKCS#1 format. Why???
RSAPrivateKey testKey = getRSAPrivateKeyFromPem(key);
} catch(NoSuchAlgorithmException | InvalidKeySpecException e) {
log.error("failed to read RSA key");
}
}
#Bean
public SomeObject anotherBean() {
SomeObjectBuilder builder = new SomeObjectBuilder();
RSAPrivateKey testKey = null;
try {
// This fails to build the key with exception: java.security.InvalidKeyException: IOException : algid parse error, not a sequence
// Okay that is expected since key is in PKCS#1 format
// What's odd here is that key is built successfully while constructing
// someRandomTestBean bean. How is that possible???
RSAPrivateKey testKey = getRSAPrivateKeyFromPem(key);
// Gets weirder here
// There is duplicate code in this legacy code base so TestUtil.getRSAPrivateKeyFromPem(...) is
// duplicate of the private function getRSAPrivateKeyFromPem from below.
// This also builds the RSAPrivateKey. How???
RSAPrivatekye testKey2 = TestUtil.getRSAPrivateKeyFromPem(key);
} catch(NoSuchAlgorithmException | InvalidKeySpecException e) {
log.error("failed to read RSA key");
}
return builder
.withKey(...)
.build();
}
private RSAPrivateKey getRSAPrivateKeyFromPem(String keyPem) {
String pem = new String(keyPem.getBytes(), StandardCharsets.UTF_8);
pem.replace("-----BEGIN RSA PRIVATE KEY-----", "");
pem.replace("-----END RSA PRIVATE KEY-----", "");
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(pem));
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}
I was able to generate a new RSA key in PKCS#8 format everything works as expected. What's puzzling here is that I am able to instantiate RSAPrivateKey in some situations but not others while using the existing key, which appears to be in PKCS#1 format. Tried to diagnose for several hours now, but I've made not insight into it.

how to generate ed25519 keypair pem file in java

I generated ed25519 keypair with my code, but when i copy the public key file and private key file to the linux machine.It looks like there is something wrong with my key pair file.
linux machine can't login with keypair file
this is my code:
public static void main(String[] args) throws Exception {
createED25519();
}
private static void createED25519() throws IOException {
KeyPairGeneratorSpi.Ed25519 ed25519 = new KeyPairGeneratorSpi.Ed25519();
ed25519.initialize(256, new SecureRandom());
KeyPair keyPair = ed25519.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
writeEd25519PrivateKey(privateKey);
writeEd25519PublicKey(publicKey);
}
private static void writeEd25519PrivateKey(PrivateKey privateKey) throws IOException {
try (PemWriter w = new PemWriter(new FileWriter("D:\\keypair\\Ed25519\\java.pem"))) {
Ed25519PrivateKeyParameters ed25519PrivateKeyParameters = (Ed25519PrivateKeyParameters) PrivateKeyFactory
.createKey(privateKey.getEncoded());
byte[] content = OpenSSHPrivateKeyUtil.encodePrivateKey(ed25519PrivateKeyParameters);
PemObject o = new PemObject("OPENSSH PRIVATE KEY", content);
w.writeObject(o);
}
}
private static void writeEd25519PublicKey(PublicKey publicKey) throws IOException {
try (FileWriter fileWriter = new FileWriter("D:\\keypair\\Ed25519\\java.pub")) {
Ed25519PublicKeyParameters publicKeyParameters = (Ed25519PublicKeyParameters) PublicKeyFactory
.createKey(publicKey.getEncoded());
String publicKeyPub = "ssh-ed25516 " + Base64.getEncoder().encodeToString(OpenSSHPublicKeyUtil.encodePublicKey(publicKeyParameters));
fileWriter.write(publicKeyPub);
}
}
pom.xml:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.67</version>
</dependency>
The content of the generated public key is:
ssh-ed25516 AAAAC3NzaC1lZDI1NTE5AAAAIJC+iPZZ56a7wogB/UxlmSbrN2hjaOnu26b2pVX6zkZr
The content of the generated private key is:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz
c2gtZWQyNTUxOQAAACCQvoj2Weemu8KIAf1MZZkm6zdoY2jp7tum9qVV+s5GawAA
AIhAEzACQBMwAgAAAAtzc2gtZWQyNTUxOQAAACCQvoj2Weemu8KIAf1MZZkm6zdo
Y2jp7tum9qVV+s5GawAAAED5xx3tLFBLSXC/SE1dSKL3vuUs9mj2+3/086sbXePu
TJC+iPZZ56a7wogB/UxlmSbrN2hjaOnu26b2pVX6zkZrAAAAAAECAwQF
-----END OPENSSH PRIVATE KEY-----
Hope someone can tell what's wrong with the code, or is there any other way to generate the ED25519 key pair file for SSH login, thanks!
I think the fact that there has been no response, is there is likely nothing wrong with your code, getting a password prompt is more indicative of sshd_config.d/overrides.conf issues. Ensure PubkeyAuthentication yes is present. Then when trying to ssh, using (multiple) -v flags to find the issues, e.g ssh -vvv user#host. This is not a java issue, unless you can't verify the public key against the private key, in code.
Edit: When looking at the verbose output, check to see if there is anything wrong with id_ed25516 rather than id_ed22519 of your public key file. That part is hardcoded via string here String publicKeyPub = "ssh-ed25516 "

KeyStore "unsupported protection parameter"

I'm trying to store a SecretKey in the Android KeyStore, and I'm even directly following the documentation found here: KeyProtection: AES Key for Encryption / Description in GCM Mode, which still doesn't work.
I seem to get the following exception when I run this:
java.security.KeyStoreException: unsupported protection parameter
This exception is specifically raised when I call keyStore.setEntry(...).
I'm running Android 10 on a Samsung Galaxy S10, if that makes any difference.
#RequiresApi(23)
private static KeyStore.ProtectionParameter getProtectionParameter() {
return new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build();
}
#RequiresApi(23)
private static SecretKey getSecretKey() throws Exception {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
if (keyStore.containsAlias(KEY_ALIAS)) {
final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore
.getEntry(KEY_ALIAS, null);
return secretKeyEntry.getSecretKey();
}
final KeyGenerator keyGenerator = KeyGenerator
.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build();
keyGenerator.init(keyGenParameterSpec);
SecretKey k = keyGenerator.generateKey();
keyStore.setEntry(
KEY_ALIAS,
new KeyStore.SecretKeyEntry(k),
getProtectionParameter()
);
return getSecretKey();
}
It turns out the issue I had was in my KeyStore.getInstance and KeyGenerator.getInstance lines. One of them was using KeyStore.getDefaultType() where as the other one was using AndroidKeyStore. Changing this got rid of the unsupported protection parameter issue.
Additionally, after fixing that I ran into an issue with updating the Protection Parameter.
It turns out, that the following section of the code is incorrect
SecretKey k = keyGenerator.generateKey();
keyStore.setEntry(
KEY_ALIAS,
new KeyStore.SecretKeyEntry(k),
getProtectionParameter()
);
It tries to insert the key into the keystore twice, since generateKey() already inserts it into the KeyStore.
The fully working code would look like this
#RequiresApi(23)
private static SecretKey getSecretKey() throws Exception {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null, null);
final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore
.getEntry(KEY_ALIAS, null);
if (secretKeyEntry != null) {
return secretKeyEntry.getSecretKey();
}
final KeyGenerator keyGenerator = KeyGenerator
.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build();
keyGenerator.init(keyGenParameterSpec);
SecretKey k = keyGenerator.generateKey();
return getSecretKey();
}

How do I retrieve a public/private key from a file using BouncyCastle?

I'm having a hard time understanding how to use a private and public key file given to me.
I have 2 files, public.pem and private.pem. I'm trying to use BouncyCastle to get the public and private keys. I wrote this class to try and extract the keys:
public class KeyReaders {
public static class PublicKeyReader {
public static byte[] get(String filename)
throws Exception {
FileReader f = new FileReader(filename);
PEMParser pp = new PEMParser(f);
SubjectPublicKeyInfo o = (SubjectPublicKeyInfo )pp.readObject();
return o.parsePublicKey().getEncoded();
}
}
public static class PrivateKeyReader {
public static byte[] get(String filename)
throws Exception {
FileReader f = new FileReader(filename);
PEMParser pp = new PEMParser(f);
PEMKeyPair o = (PEMKeyPair)pp.readObject();
return o.getPrivateKeyInfo().getEncoded();
}
}
}
I can't seem to figure out how to use these keys to decode a file. I have a file, test.txt, which I can't use the private key to decode. I'm not 100% sure this is even the appropriate way to read in a .PEM file.
So, how do I use BouncyCastle to decode a text file, given the private key file?
I'm assuming you are trying to produce a regular JCA key pair. Have you tried using the JcaPEMKeyConverter class? It is in the org.bouncycastle.openssl.jcajce package.

Categories

Resources