I need to know how to generate a String of a SecretKey and convert it back into a SecretKey.
I first generated a SecretKey using the KeyGenerator like in the code below and I used it and it worked, but I also saved the SecretKey as a private value using getEncoded(). Now when I regenerate the SecretKey and use it in my code I get the error:
W/System.err: java.security.InvalidKeyException: Unsupported key size: 43 bytes
I thought the following code should result in logging two equivalent Strings, but it does not.
KeyGenerator keyGen = null;
keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey key= keygen.generateKey();
byte[] keyBytes = key.getEncoded();
SecretKey keyCopy = new SecretKeySpec(keyBytes, "AES");
Log.d("key string: ", key.getEncoded().toString());
Log.d("keyCopy string: ", keyCopy.getEncoded().toString());
As per the comments I edited the above code from byte[] keyBytes = key.getEncoded().toString().getBytes(); to byte[] keyBytes = key.getEncoded(); removing redundancy.
As the comments have stated. toString() does not return a representation of the object itself, in this case, but something variable. While it returns values that differ for each byte array, encoding them into base65 using Base64.encodeToString(key.getEncoded(), Base64.DEFAULT) results in equivalent representations of both the original key and its copy.
KeyGenerator keyGen = null;
keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256);
SecretKey key= keygen.generateKey();
byte[] keyBytes = key.getEncoded();
SecretKey keyCopy = new SecretKeySpec(keyBytes, "AES");
Log.d("key string: ", Base64.encodeToString(key.getEncoded(), Base64.DEFAULT));
Log.d("keyCopy string: ", Base64.encodeToString(keyCopy.getEncoded(), Base64.DEFAULT));
Related
I am trying to implement PBKDF2 with Hmac Sha1 in my android app for encrypting the password.
But the encoded key is too short and returns incorrect value comparing to what i get from https://8gwifi.org/pbkdf.jsp website.
Below is the code i use
char [] salt="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".toCharArray();
byte [] serversalt="E4jmftOIsX4TYB6qPUuX6VteIKExLfgQ9I9DTY5VbOTRT7NGqrgc!1130053051!1657429480328".getBytes();
try {
SecretKey sk=generateKey1(salt,serversalt);
System.out.println("key:"+sk.getEncoded().toString());
}catch (Exception e){ System.out.println(e.toString());
public static SecretKey generateKey1(char[] passphraseOrPin, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, 4, 128);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
return secretKey;
}
Expected key is 7b3318d9fedb813a3c474ec043681fef
but i'm getting [B#b5971bf
Try use:
SecretKey sk = generateKey1(salt,serversalt);
String key = Base64.encodeToString(sk.getEncoded(), Base64.DEFAULT);
In my case is working and key is the same as i get from https://8gwifi.org/pbkdf.jsp website.
i already wandered in many stackoverflows post but still cant figured out whats wrong with my code.
public class KripAsim {
String hasil;
public String encrypt(String text) {
try {
String PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvCNqSslgCndo8vfNrkXFDLXmst024Oi8D7LEiJFjYBva4kBKKISe8rKp58kCLLHjv90RN+Dy2KWcf0eFkKaqc3zILBI99JhV1z8TFOzmt5dfgW6fD1ucBfsK6pWxK84DddyOqKldwHlReqjuDHT2jLue51vpXaCa12WV5bMnGsfy3vZKnp699YCguqRpTR1MijZ9pz8WqldrR0a/DCaq5YxZ7lvjwuWIodQy3S3XRHAaeaUrFHFFLumzXAGuP447oRYR0p+1qsy8+wOtrsGm8m8bMg+C1XGMblkODtOFHz3wtrRZ5OwzgEm7J7odmSX8mSYBZYLcnUVqIFRsQkZLiwIDAQAB";
byte [] decoded = Base64.decode(PUBLIC_KEY,Base64.NO_WRAP);
KeyFactory keyFac = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decoded);
PublicKey pubkey = keyFac.generatePublic(keySpec);
Cipher rsa;
rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, pubkey);
hasil = Base64.encodeToString(rsa.doFinal(text.getBytes("UTF-8")),Base64.NO_WRAP);
return hasil;
} catch (Exception e) {
e.printStackTrace();
}
return hasil;
}
}
it returns null. please help. thanks in advance
The line PublicKey pubkey = keyFac.generatePublic(keySpec); throws an InvalidKeySpecException because you have incorrectly supplied a PKCS8EncodedKeySpec when you should have supplied an X509EncodedKeySpec.
You should also completely specify the transformation string in the Cipher.getInstance() method. The following fragment taken from your code illustrates this:
byte[] decoded = Base64.decode(PUBLIC_KEY, Base64.DEFAULT);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decoded);
PublicKey pubkey = KeyFactory.getInstance("RSA").generatePublic(keySpec);
Cipher rsa = Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding");
rsa.init(Cipher.ENCRYPT_MODE, pubkey);
String hasil = Base64.encodeToString(rsa.doFinal(text.getBytes("UTF-8")),
Base64.NO_WRAP);
return hasil;
Finally, you should avoid encrypting data directly with RSA. The correct method is to use a hybrid encryption scheme in which the data is encrypted with a block cipher, say AES in GCM mode, using a randomly generated AES key, and then this key is encrypted using RSA. There are many examples of this around for reference.
I currently have an accessory that uses AES/CBC without a random number on the key. Instead, the message itself includes a random number and the key is hard-coded. I'm trying to do the same thing on my Android to exchange with the accessory through BLE. Somehow I can't figure out how generate a Key-class object without using a random number.
Here's an example of what I'd like to be able to do:
public byte[] encrypt(byte[] key, byte[] input) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding ");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(input);
}
Here's what I've tried:
public byte[] encrypt(byte[] key, byte[] input) throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = new SecureRandom(key);
secureRandom.setSeed(key);
keyGenerator.init(128, secureRandom);
SecretKey secretkey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding ");
cipher.init(Cipher.ENCRYPT_MODE, secretkey);
return cipher.doFinal(input);
}
public byte[] encrypt(byte[] key, byte[] input) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES/CBC/NoPadding ");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding ");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
return cipher.doFinal(input);
}
Unfortunately both of those alter the key before the encryption.
How can I use my key "as is"?
If you want to encrypt with your own key without salt or using any random, you can do as following.
byte[] keyBuf= new byte[32];
byte[] b= key.getBytes("UTF-8");
int len= b.length;
if (len > keyBuf.length) len = keyBuf.length;
System.arraycopy(b, 0, keyBuf, 0, len);
SecretKey keySpec = new SecretKeySpec(keyBuf, "AES");
byte[] ivBuf= new byte[16];
IvParameterSpec ivSpec = new IvParameterSpec(ivBuf);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
Where key is my custom key as a String and b my key as a bytes[]. Initializing the cipher this way avoid the salting and allow you to always use your own key to encrypt anything.
The following method does not work. decodedMessage ends up with garbage in it instead of the expected results.
I'm following an example here that supposedly works.
public static void POCSimple()
{
String secretMessage = "short message";
PublicKey publicKey = null;
PrivateKey privateKey = null;
String encodedMessage = "";
byte[] encodedBytes = null;
String decodedMessage ="";
byte[] decodedBytes = null;
try
{
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
Cipher c1 = Cipher.getInstance("RSA");
c1.init(Cipher.ENCRYPT_MODE, publicKey);
encodedBytes = c1.doFinal(secretMessage.getBytes());
encodedMessage = Base64.encodeToString(encodedBytes, Base64.DEFAULT);
Cipher c2 = Cipher.getInstance("RSA");
c2.init(Cipher.DECRYPT_MODE, privateKey);
decodedBytes = c2.doFinal(encodedBytes);
decodedMessage = Base64.encodeToString(decodedBytes, Base64.DEFAULT);
String mystring = "look at results";
}
catch (Exception e)
{
String status = e.toString();
}
}
Any help would be most appreciated.
Thanks,
Dean
Of course you are getting garbage, this is your sequence:
Plaintext message -> Encrypt -> Encode -> Encoded message
Encoded message -> Decrypt -> Decode -> GARBAGE
You need to undo the Base64 encoding before you can decrypt the message, you are doing the reverse process in the incorrect order!
Edit
Actually its worse, this is your sequence:
Plaintext message -> Encrypt -> Encode -> Encoded message
Encrypted message -> Decrypt -> Encode -> GARBAGE
Try this:
Cipher c1 = Cipher.getInstance("RSA");
c1.init(Cipher.ENCRYPT_MODE, publicKey);
encodedBytes = c1.doFinal(secretMessage.getBytes());
encodedMessage = Base64.encodeToString(encodedBytes, Base64.DEFAULT);
Cipher c2 = Cipher.getInstance("RSA");
c2.init(Cipher.DECRYPT_MODE, privateKey)
decodedBytes = Base64.decode(encodedMessage.toByteArray(), Base64.DEFAULT);
decryptedMessage = c2.doFinal(decodedBytes);
It turns out that in my original code, decodedBytes contained the properly decrypted bytes. The following command was turning decodedBytes into junk characters ...
decodedMessage = Base64.encodeToString(decodedBytes, Base64.DEFAULT);
I replaced that code with ...
String str = new String(decodedBytes, "UTF-8");
And this solved the problem probably because decodedBytes had never been Base64 encoded in the first place.
I also found that using straight RSA I can only encrypt a maximum of 245 bytes if I use a 2048 bit key. less if I use a 1024 bit key.
If larger strings need to be encrypted using asymmetric Public/Private keys then I need to first encrypt a string using symmetric AES and then encrypt the AES key with the public RSA key and send both the encrypted AES key and the encrypted message over the wire where the receiver can decrypt the AES key using their private RSA key. The AES key can be randomly generated in the sending code.
I want to encrypt/decrypt some passwords in the SQLite database of my application. To do that I have searched on the internet and I have found the AES algorithm.
I have this code:
public String encript(String dataToEncrypt)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
// I'm using AES encription
if(!dataToEncrypt.equals("")){
String key = "FMVWf8d_sm#fz";
Cipher c = Cipher.getInstance("AES");
SecretKeySpec k;
try {
k = new SecretKeySpec(key.getBytes(), "AES");
c.init(Cipher.ENCRYPT_MODE, k);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return new String(c.doFinal(Base64.decode(dataToEncrypt)));
}
return "";
}
public String decript(String encryptedData)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
if(!encryptedData.equals("")){
String key = "FMVWf8d_sm#fz";
Cipher c = Cipher.getInstance("AES");
SecretKeySpec k = new SecretKeySpec(Base64.decode(key), "AES");
c.init(Cipher.DECRYPT_MODE, k);
return new String(c.doFinal(Base64.decode(encryptedData)));
}
return "";
}
After running this I get this error on encrypt method:
01-27 14:50:51.698: ERROR/ACTIVITY(782):
java.security.InvalidKeyException: Key length not 128/192/256 bits.
I have seen some other cases here on stackoverflow but I want to give the key to the AES not to generate it...
Can somebody help me with this? If there is other encryption method to use but without using another jars or external classes and to let me give the key.
Thank you very much!
The error message makes it perfectly clear: your encryption key must be of certain size: 128, 192 or 256 bits. And your key is 104 bits. Note, that as you want to use only printable characters in your key, the length of the key should be 192 or longer bits, cause your alphabet (set of characters that you use) makes encryption weaker.
Usual practice is such:
Get password (in your case String key = "FMVWf8d_sm#fz";)
Generate using some hash function key with length 128, 192 or 256
Put it into encryption algorithm
Have fun
So you are missing key generation stage. Do smth like:
// Get the KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available
// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted =
cipher.doFinal((args.length == 0 ?
"This is just an example" : args[0]).getBytes());
System.out.println("encrypted string: " + asHex(encrypted));
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original =
cipher.doFinal(encrypted);
String originalString = new String(original);
System.out.println("Original string: " +
originalString + " " + asHex(original));