HSM decryption + encryption chaining
Asked Answered
O

1

4

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.

Ordain answered 30/7, 2019 at 6:10 Comment(12)
I think you can do this with key wrapping. Use the sender's private key to unwrap the per-message symmetric key: you get a handle to the symmetric key, not the symmetric itself, and then you wrap that with the next receiver's public key.Rimose
Some HSMs provides translate data feature, where you can translate(decrypt with key1 and encrypt with key2) the data from incoming data key1 to outgoing key key2, the operation takes place inside HSM so you wont really be touching clear data, but these commands looks to be with symmetric keys only, you will have to device key exchange mechanism for the symmetric data key in that caseTravelled
...I've generated a keypair for the sender... Well then, the game is over, you can read all their messages.Breughel
AFAIK none of the common cryptographic APIs support secure re-encryption. BTW I answered similar question for PKCS#11 interface few months ago.Biegel
@Travelled can you please be more specific about the HSM vendor/model that provides "translate data feature"?Biegel
@Biegel Atalla Ax160 models support translate dataTravelled
@Travelled Thanks, will check out those HSMs.Ordain
@Giles will look into that. The payload is indeed a symmetric key in this case, but I have no information about it’s format or generation. I don’t know if the HSM will recognize it as being crypto material and give me an opaque handler.Ordain
@JamesKPolk yes, but the sender is paying me a great deal of money to fan out the message securely to tens of thousands of devices whose public keys I’m managing. They trust me to do it right, which is why they’ve encrypted it with the public key I gave them. I’m trying to make sure the payload gets to all its destinations without me or my team or employees or hackers ever being able to see it.Ordain
Many HSM's have methods for key derivation using XOR. For XOR you can decrypt / encrypt in any order. As for the type of key, just say that it is a HMAC key, a HMAC key can have any size (although I would not be surprised if HSM's will still restrict you to certain sizes).Prokofiev
As Gilles wrote above, simple unwrapping into a session-only generic secret key, which then can be wrapped for all the recipients and deleted should work.....And which particular HSM are you using? Some specific settings (e.g. policy, unwrap template) can be (and should be) further used to tighten what is allowed to do with the stored/imported key material.Mandle
A Thales nCipher series, don't know the exact model. Think we're just going to go with CodeSafe SEE and write C/C++ to run inside the HSM. Need to do some other checks as well anyway.Ordain
M
5

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!

Mandle answered 2/8, 2019 at 22:6 Comment(4)
I'm afraid this solution does not fulfill OP's requirement "without having the decrypted message anywhere near my application memory".Biegel
@Biegel Why -- decrypted message is inside HSM as a generic secret key. The application has only a handle for this key. Given the template of this generic secret key it is SENSITIVE...All the application does with the key is that it wraps it with public keys of "the recipients" (whoever they are)...Mandle
I'm sorry I didn't notice that you were using generic secret key. That's very interesting idea worth exploring! Now I wonder what's the size limit for generic key value.Biegel
@Biegel I have never tried, but Luna 7 claims to support generation (via CKM_GENERIC_SECRET_KEY_GEN) of up to 512 bytes long generic secret keys. Also note that wrap/unwrap key has no multi-part variants.Mandle

© 2022 - 2024 — McMap. All rights reserved.