I am trying to interface with external system which requires to send an RSA-OAEP SHA-256 public key with key size of 2048.
I am getting an error that the key has wrong bit length: '2350' .
I tried online encryption/decryption services using the generated KP and they seems to accept the key. What I am doing wrong?
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
SecureRandom random = new SecureRandom();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");
generator.initialize(2048, random);
KeyPair pair = generator.generateKeyPair();
Key pubKey = pair.getPublic();
Key privKey = pair.getPrivate();
// I am sending pubKey.getEncoded()
Example result of the public key:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuUKRnE07rwQ8Juegbhabv1kaHOrfou8+FNHYyhjn8jUPgwumALonsvztt4goivc1Bwm6sFwCIGnxf+2y1BI1saG3w5S1R24EUAN7efi7CS4LMEhtgJtavtWYEkEZj7OaU/BLnkB1rFAmBDU3vudSd3Gupgnbqtw7VjOH6Qrfnsh3phVr6DdHruq7SftOvCyhBucOax0hwt6enRs5UjBfbgDbbSMFaFdF4jZpE4Jnfl9gwRF51QP934Il1djPT6cezuEYlD8VAklLFPR+rOL73nvBCxLdZwdBlQHO8J8XGjWaNmAMHvyisFxkD8Ud9nC7m9MPb9J6+n3cWG7OL+C97QIDAQAB
Thank you
Related
Is there a way to validate in java if the given private key, say certain *.key file matches with the certain public key, to a certain .pub file using RSA algorithm?
You can verify if a key pair matches by
creating a challenge (random byte sequence of sufficient length)
signing the challenge with the private key
verifying the signature using the public key
This gives you a sufficiently high confidence (almost certainity) that a key pair matches if the signature verification is ok, and an absolute certainity that a key pair does not match otherwise.
Example code:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// create a challenge
byte[] challenge = new byte[10000];
ThreadLocalRandom.current().nextBytes(challenge);
// sign using the private key
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(privateKey);
sig.update(challenge);
byte[] signature = sig.sign();
// verify signature using the public key
sig.initVerify(publicKey);
sig.update(challenge);
boolean keyPairMatches = sig.verify(signature);
This also works with Elliptic Curve (EC) key pairs, but you need to use a different signature algorithm (SHA256withECDSA):
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(new ECGenParameterSpec("sect571k1"));
...
Signature sig = Signature.getInstance("SHA256withECDSA");
The answer that was marked as being correct wastes a lot of CPU cycles. This answer is waaaay more CPU efficient:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) keyPair.getPrivate();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
// comment this out to verify the behavior when the keys are different
//keyPair = keyGen.generateKeyPair();
//publicKey = (RSAPublicKey) keyPair.getPublic();
boolean keyPairMatches = privateKey.getModulus().equals(publicKey.getModulus()) &&
privateKey.getPublicExponent().equals(publicKey.getPublicExponent());
(the other answer signs a message with the private key and then verifies it with the public key whereas my answer checks to see if the modulus and public exponent are the same)
boolean keyPairMatches = privateKey.getModulus().equals(publicKey.getModulus()) && privateKey.getPublicExponent().equals(publicKey.getPublicExponent());
java.security.interfaces.RSAPrivateKey doesn't have getPublicExponent() method.
org.bouncycastle.asn1.pkcs.RSAPrivateKey has getPublicExponent() method.
So,if you don't want to use bouncycastle, you have to use the sign&verify answer.
I have an issue with my java code. I'm trying to encrypt a file. However, when I run my java code I get "java.security.InvalidKeyException: Invalid AES key length: 162 bytes".
Here is the code:
byte[] rawFile;
File f = new File("./src/wonkybox.stl");
FileInputStream fileReader = new FileInputStream(f);
rawFile = new byte[(int)f.length()];
fileReader.read(rawFile);
/***** Encrypt the file (CAN DO THIS ONCE!) ***********/
//Generate the public/private keys
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("AES");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG","SUN");
keyGen.initialize(1024, random);
KeyPair key = keyGen.generateKeyPair();
PrivateKey privKey = key.getPrivate();
PublicKey pubKey = key.getPublic();
//Store the keys
byte[] pkey = pubKey.getEncoded();
FileOutputStream keyfos = new FileOutputStream("./CloudStore/keys/pubkey");
keyfos.write(pkey);
keyfos.close();
pkey = privKey.getEncoded();
keyfos = new FileOutputStream("./CloudStore/keys/privkey");
keyfos.write(pkey);
keyfos.close();
//Read public/private keys
KeyFactory keyFactory = KeyFactory.getInstance("AES");
FileInputStream keyfis = new FileInputStream("./CloudStore/keys/pubkey");
byte[] encKey = new byte[keyfis.available()];
keyfis.read(encKey);
keyfis.close();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
PublicKey pub1Key = keyFactory.generatePublic(pubKeySpec);
keyfis = new FileInputStream("./CloudStore/keys/privkey");
encKey = new byte[keyfis.available()];
keyfis.read(encKey);
keyfis.close();
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encKey);
PrivateKey priv1key = keyFactory.generatePrivate(privKeySpec);
//Encrypt file using public key
Cipher cipher = Cipher.getInstance("AES");
System.out.println("provider= " + cipher.getProvider());
cipher.init(Cipher.ENCRYPT_MODE, pub1Key);
byte[] encryptedFile;
encryptedFile = cipher.doFinal(rawFile);
//Write encrypted file to 'CloudStore' folder
FileOutputStream fileEncryptOutput = new FileOutputStream(new File("./CloudStore/encrypted.txt"));
fileEncryptOutput.write(encryptedFile);
fileEncryptOutput.close();
The error occurs at the line "KeyPairGenerator keyGen = KeyPairGenerator.getInstance("AES");".
AES is a symmetric algorithm, hence they use of KeyPairGenerator is not supported. To generate a key with AES you call KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); //set keysize, can be 128, 192, and 256
By looking at the rest of your code, it looks like you are trying to achive asymmetric encryption (since you call getPublic() and getPrivate() etc), so I advice you to switch to using RSA or any other asymmetric algorithm that java supports. You will most likley only need to replace AES with RSA in your getInstance(); calls, and pherhaps some fine-tuning. Good luck
As far as I know, AES is symmetric encryption algorithm i.e. it needs only one key for encryption/decryption.
From the JavaDoc of java.security.KeyPairGenerator:
The KeyPairGenerator class is used to generate pairs of public and private keys.
Meaning that it should be used for asymmetric encryption algorithms. For symmetric encryption algorithms one should use javax.crypto.KeyGenerator.
However, I advise simply mimicking some tutorial on how to encrypt / decrypt byte array in Java using AES like this one.
It uses sun.misc.Base64Encoder / Base64Decoder classes to encode / decode byte array to / from String, however you may skip this step.
Hope this helps
How can you use a keypair generator for AES? AES is a symmetric key algorithm. Refer this link. That means if you encrypt data using a key "k", then you will have to decrypt it also using the same key "k". But when you generate key pair, as the name suggests, two keys are generated and if you encrypt using one of the keys, you can decrypt only using the other key. This is the base for PKI.
If you want to use keypair generator use an algorithm like "rsa" or "dsa" in the getInstance() method like this :
KeyPairGenerator keygen=KeyPairGenerator.getInstance("rsa");
I think your code should now work fine after making the above change.
I have the following code that signs some String data:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
keyGen.initialize(1024, random);
KeyPair pair = keyGen.generateKeyPair();
PrivateKey privateK = pair.getPrivate();
PublicKey publicK = pair.getPublic();
Signature dsa = Signature.getInstance("SHA1withDSA");
dsa.initSign(privateK);
dsa.update(data.getBytes());
byte[] signature = dsa.sign();
String hexSignature = DatatypeConverter.printHexBinary(signature);
String hexPublicK = DatatypeConverter.printHexBinary(publicK.getEncoded());
However, it's giving me a varying public key size and signature size.
For example,
Why is that? I want both the public key and the signature produced for some data to have fixed sizes.
Thank you for your help!
I'm using IBM SDK Java Technology Edition and the code below:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
SecureRandom random = SecureRandom.getInstance("IBMSecureRandom", "IBMJCE");
random.setSeed(longToBytes(System.currentTimeMillis()));
keyGen.initialize(512, random);
KeyPair pairTytus = keyGen.generateKeyPair();
KeyPair pairRomek = keyGen.generateKeyPair();
KeyPair pairAtomek = keyGen.generateKeyPair();
// Making a wrap-key for private keys; based on password.
byte[] key = ("password").getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "MARS");
Cipher c1 = Cipher.getInstance("MARS/ECB/NoPadding");
c1.init(Cipher.WRAP_MODE, secretKeySpec);
c1.wrap(pairTytus.getPrivate());
While running the application I'm getting this exception:
Exception in thread "main" javax.crypto.IllegalBlockSizeException:
Input length not multiple of 16 bytes.
I read somewhere it has something to do with using "NoPadding", but MARS doesn't implement any padding in this library. Any thoughts how to avoid this exception?
I need to use both MARS and ECB in this place.
I am making an application which generates a key pair for a user. But in every device the keys are identical. Here is my code:
public KeyPair generateKeys() {
KeyPair keyPair = null;
try {
// get instance of rsa cipher
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024); // initialize key generator
keyPair = keyGen.generateKeyPair(); // generate pair of keys
} catch(GeneralSecurityException e) {
System.out.println(e);
}
return keyPair;
}
And to show the generated keys code is:
KeyPair keyPair = rsa.generateKeys();
byte[] publicKey = keyPair.getPublic().getEncoded();
byte[] privateKey = keyPair.getPrivate().getEncoded();
privateText.setText( Base64.encodeToString(privateKey, Base64.NO_WRAP) );
publicText.setText( Base64.encodeToString(publicKey, Base64.NO_WRAP) );
The key generation is called only one time for each android device, and for that reason the keys in each device should be different.. Can anyone tell me what i am missing here?
I believe you are only looking at the first few or last few bits. I thought I had the same problem too but when I looked at the bits in the middle, they were indeed different!