Decryption failed when storing the key inside Java key store - encryption

I've created an encryption key by the following code:
SecretKeyFactory skFactory = SecretKeyFactory.getInstance("PBEWithSHA1AndDESede");
SecretKey key = skFactory.generateSecret(new PBEKeySpec("<some password>".toCharArray()));
Then I've used the key to encrypt some text.
I've stored this key inside a java key store and saved in on FS:
KeyStore ks = KeyStore.getInstance("JCEKS");
ks.setKeyEntry(keyAlias, key ,keyPassword.toCharArray(), null);
FileOutputStream fileOutputStream = new FileOutputStream (keyStorePath);
keyStore.store(fileOutputStream , keyStorePassword.toCharArray());
fileOutputStream.close();
In a different process I open the key store and try to decrypt some text:
KeyStore ks2 = KeyStore.getInstance("JCEKS");
ks2.load(new java.io.FileInputStream(keyStorePath), ksPassword.toCharArray());
SecretKeyFactory skFactory2 = SecretKeyFactory.getInstance("PBEWithSHA1AndDESede");
String passForTheKey = ks2.getKey(keyAlias, keyPass.toCharArray()).toString();
KeySpec key = new PBEKeySpec(passForTheKey.toCharArray());
SecretKey sKey2 = skFactory.generateSecret(key);
When trying to decrypt the text I get the error:
java.security.InvalidKeyException: Given final block not properly padded
If I try to use the key without storing it in the key store immediately after creating it, the decription proccess is working great.
Any ideas?

You're storing the actual secret key in your keystore (which is normal). However, you seem to be trying to read it as a password, for a new key you're generating later.
Instead of this:
String passForTheKey = ks2.getKey(keyAlias, keyPass.toCharArray()).toString();
KeySpec key = new PBEKeySpec(passForTheKey.toCharArray());
SecretKey sKey2 = skFactory.generateSecret(key);
use this:
SecretKey sKey2 = (SecretKey) ks2.getKey(keyAlias, keyPassword.toCharArray());
What you're reading from the keystore is the key itself (as you've stored it), not some password. (generateSecret will just generate a new key.)

Related

HSM decryption + encryption chaining

My application is acting as a switchboard to transfer very sensitive messages between two parties and I'm trying to figure out how I can do this without "looking" at the message they're trying to send.
I have a HSM, and I've generated a keypair for the sender - they're going to encrypt the message with their public key that I gave them, and I can decrypt the message using the private key I have in the HSM.
I'm going to then pass that message on by encrypting it with the public key of the ultimate receiver, which I have.
Is there any way to chain these two operations inside the HSM, without having the decrypted message anywhere near my application memory? I would like the plaintext content to never leave the boundaries of the HSM.
I know that some HSMs have a CodeSafe / SEE machine feature that lets me write embedded system code and run it inside the HSM, before I get into that I'd like to see if there's a way using the general PKCS / JCE / CNG APIs to do this safely.
If all you need is to re-encrypt the same secret under a different key, you can use C_Unwrap to create a temporal HSM object with value of the translated secret and then use C_Wrap to encrypt the value of this temporal HSM object for all the recipients.
This way the secret will never leave HSM.
Something like this (verified to be working on SafeNet Luna 7 with RSA-OAEP):
// Your private key for 'decrypting' secret. Must have key unwrapping allowed
CK_OBJECT_HANDLE hsmPrivateKey = ... ;
// Encrypted secret
byte[] wrappedKey = ... ; //
// Template for temporal generic secret key with value of the secret
CK_ATTRIBUTE[] tempTemplate = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA.CLASS, CKO.SECRET_KEY),
new CK_ATTRIBUTE(CKA.KEY_TYPE, CKK.GENERIC_SECRET),
new CK_ATTRIBUTE(CKA.TOKEN, false),
new CK_ATTRIBUTE(CKA.PRIVATE, true),
new CK_ATTRIBUTE(CKA.EXTRACTABLE, true),
new CK_ATTRIBUTE(CKA.SENSITIVE, true),
new CK_ATTRIBUTE(CKA.ENCRYPT, false),
new CK_ATTRIBUTE(CKA.DECRYPT, false),
new CK_ATTRIBUTE(CKA.WRAP, false),
new CK_ATTRIBUTE(CKA.UNWRAP, false),
new CK_ATTRIBUTE(CKA.SIGN, false),
new CK_ATTRIBUTE(CKA.VERIFY, false),
new CK_ATTRIBUTE(CKA.DERIVE, false)
};
// Unwrapping/decryption mechanism
CK_MECHANISM mechanism = ... ;
// Handle for temporal generic secret key with value of the secret
CK_OBJECT_HANDLE temporalValueHandle = new CK_OBJECT_HANDLE();
// Unwrap/decrypt the secret into temporal key
CryptokiEx.C_UnwrapKey(session, mechanism, hsmPrivateKey, wrappedKey, wrappedKey.length, tempTemplate, tempTemplate.length, temporalValueHandle);
// Wrap/encrypt the secret for recipients. Recipient public keys must have key wrapping allowed
for(CK_OBJECT_HANDLE recipientPublicKey : ... ) {
LongRef resSize = new LongRef(0);
CryptokiEx.C_WrapKey(session, mechanism, recipientPublicKey, temporalValueHandle, null, resSize);
byte[] rewrappedKey = new byte[CryptokiUtils.safeIntCast(resSize.value)];
CryptokiEx.C_WrapKey(session, mechanism, recipientPublicKey, temporalValueHandle, rewrappedKey, resSize);
System.out.println("Re-wrapped key: " + bytesToHexString(rewrappedKey));
}
// Delete temporal generic secret key
CryptokiEx.C_DestroyObject(session, temporalValueHandle);
Good luck!

I want to store key value pair(Key and Value) into android keystore

I followed the bellow sample
https://nelenkov.blogspot.in/2012/05/storing-application-secrets-in-androids.html
It worked fine till marshmallow in marshmallow it is giving some exception and I am not able to store the Key and value pair to keystore.
Bellow code I am getting exception
For this last step there seem to be two options:
keyStore.setKeyEntry(String alias, byte[] key, Certificate[] chain);
or
keyStore.setKeyEntry(String alias, Key key, char[] password, Certificate[] chain);
I started with the second of the two, but received java.security.KeyStoreException: entries cannot be protected with passwords .... Okay, that's odd, why would there be a method that guarantees to throw an exception? Let's try door number 1.
At which point, when I call setKeyEntry, and pass keyPair.getPrivate().getEncoded() as the second argument, I receive java.security.KeyStoreException: Operation not supported because key encoding is unknown from the system.
byte[] encodedKey = Base64.encode("keytostore".getBytes(),
Base64.DEFAULT);
SecretKey originalKey = new SecretKeySpec(encodedKey, 0,
encodedKey.length, "AES");
KeyStore instance = KeyStore.getInstance("AndroidKeyStore");
instance.load(null);
instance.setEntry(
"key1",
new KeyStore.SecretKeyEntry(originalKey),
new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT
| KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(
KeyProperties.ENCRYPTION_PADDING_NONE)
.build());

Client certificates access key (encrypted)

I have a client certificate files (.perm,.csr,.pfx,.key) and these files contain hex code
The below code snippet takes a cipherText and performs some validation. This is a servlet and the cipherText is passed as a request paramter. I looked into cert files and provided all the hex code available in those files as input but nothing seem to work.
Looking at the way its decoded can anyone tell what kind of input its expecting from the certificate files:
validate(cipherText)
private static final byte[] desKeyData = {
(byte)0xA2, (byte)0x15, (byte)0x37, (byte)0x07, (byte)0xCB, (byte)0x62,
(byte)0xC1, (byte)0xD3, (byte)0xF8, (byte)0xF1, (byte)0x97, (byte)0xDF,
(byte)0xD0, (byte)0x13, (byte)0x4F, (byte)0x79, (byte)0x01, (byte)0x67,
(byte)0x7A, (byte)0x85, (byte)0x94, (byte)0x16, (byte)0x31, (byte)0x88 };
byte[] bCipherText = Base64.decode(CipherText);
Cipher oC3des = Cipher.getInstance("DESede/CBC/PKCS5Padding");
SecretKeySpec oKey = new SecretKeySpec(s_desKeyData , "DESede");
IvParameterSpec oIvSpec = new IvParameterSpec(s_baIV);
oC3des.init(Cipher.DECRYPT_MODE, oKey, oIvSpec);
byte[] plaintext = oC3des.doFinal(bCipherText );
return new String(plainText, Charset.forName("UTF-8"));

Migrating users to Universal Membership Provider

I'm trying to migrate to the new Universal Membership providers (from a home brew solution). I've migrated our old User table to the Users/Memberships table.
When I run Membership.ValidateUser(txtUsername.Text.Trim(), txtPassword.Text.Trim()), it always returns false, even though I know the username/password is correct.
Here is how I generated the password, hash, and salt:
var salt = Crypto.GenerateSalt();
var hashedPassword = this.GenerateHashWithSalt(password, salt);
This is the GenerateHashWithSalt method I'm using
private string GenerateHashWithSalt(string password, string salt)
{
string hashWithSalt = password + salt;
byte[] saltedHashBytes = Encoding.UTF8.GetBytes(hashWithSalt);
HashAlgorithm algo = HashAlgorithm.Create(Membership.HashAlgorithmType);
byte[] hash = algo.ComputeHash(saltedHashBytes);
return Convert.ToBase64String(hash);
}
I've also gone with:
var salt = Crypto.GenerateSalt();
var saltedPassword = password + salt;
var hashedPassword = Crypto.HashPassword(saltedPassword);
Neither of these seem to work. What am I missing?
Scott
Bah, answered it.
So step 1 of all of this was migrating users from our 2-way encrypted passwords to 1 way hash.
Every example I saw of doing that included hashing the password manually. Turns out Membership.CreateUser(username,password); hashes the password (and salts), so I was hashing a hashed password, which is why auth was failing.
I simply had to call Membership.CreateUser, passing in the username & plain text pass, and it worked. Weee!

AES256 encryption and decryption in ASP

I have to send a username and password from my iphone app to a ASP server page, and I will encrypt them using: http://iphonedevelopment.blogspot.com/2009/02/strong-encryption-for-cocoa-cocoa-touch.html. What is the best way to decrypt these strings on the ASP page? I found some examples, but since the encryption will happen on two completely unrelated sides, I think I need to hard code the key in on both sides, and I can't find any examples that don't have use generated keys.
Thanks!
Yes, key management is a big problem. You will have to have the keys on both sides, on iOS you can save the key in the Keychain, that is secure but the process to get it there securely is more difficult.
The other main issue is getting all the parameters the same on both sides. Of particular interest are
encryption key value and size
mode: CBC, ECB, etc. (you should probably be using CBC)
initialization vector (iv) is needed for most modes
padding method: PKCS7, etc. (AES is a block cypher and needs input
in a multiple of block size)
Why not store the passwords in the database with SHA1, then use HMAC with a client specified key for the communication?
Have the server generate a random key and send it with the login request. The client computes the SHA1 hash of the password, then computes the HMAC SHA1 hash of that using the server-specified key. The server then verifies that the result is correct.
On the client end:
// password is the plaintext password
// keyb64 is a random key specified by the server, encoded in base64.
string ComputeSecureHash(string password, string keyb64)
{
byte[] data = Encoding.UTF8.GetBytes(password);
byte[] key = Convert.FromBase64String(keyb64);
byte[] hash;
byte[] machash;
// compute a plain SHA1 hash of the specified data
using (SHA1Managed sha1 = new SHA1Managed())
{
hash = sha1.ComputeHash(data);
}
// now compute a HMAC hash of that hash, using the random key.
using (HMACSHA1 sha1mac = new HMACSHA1(key))
{
machash = sha1mac.ComputeHash(hash);
}
return Convert.ToBase64String(machash);
}
On the server end:
// hash is the string produced by the function above
// realHash is the SHA1 hash of the real password, which you've fetched from the db
// key is the key you generated for this login session
bool VerifyHash(string hash, byte[] realHash, byte[] key)
{
byte[] machash;
using (HMACSHA1 sha1mac = new HMACSHA1(key))
{
machash = sha1mac.ComputeHash(realHash);
}
return (Convert.ToBase64String(machash) == hash);
}
This allows you to authenticate over a plaintext medium without having the password cracked.

Resources