Encryption HSM解密+;加密链

Encryption HSM解密+;加密链,encryption,pkcs#11,jce,hsm,cng,Encryption,Pkcs#11,Jce,Hsm,Cng,我的应用程序就像一个交换机,在双方之间传输非常敏感的消息,我试图弄清楚如何在不“查看”他们试图发送的消息的情况下做到这一点 我有一个HSM,我为发送者生成了一个密钥对-他们将用我给他们的公钥加密消息,我可以用HSM中的私钥解密消息 然后,我将通过使用最终接收者的公钥对其进行加密来传递该消息,我拥有该公钥 有没有办法在HSM中链接这两个操作,而不让解密的消息靠近我的应用程序内存?我希望明文内容永远不要离开HSM的边界 我知道有些HSM具有CodeSafe/SEE machine功能,可以让我编写嵌

我的应用程序就像一个交换机,在双方之间传输非常敏感的消息,我试图弄清楚如何在不“查看”他们试图发送的消息的情况下做到这一点

我有一个HSM,我为发送者生成了一个密钥对-他们将用我给他们的公钥加密消息,我可以用HSM中的私钥解密消息

然后,我将通过使用最终接收者的公钥对其进行加密来传递该消息,我拥有该公钥

有没有办法在HSM中链接这两个操作,而不让解密的消息靠近我的应用程序内存?我希望明文内容永远不要离开HSM的边界


我知道有些HSM具有CodeSafe/SEE machine功能,可以让我编写嵌入式系统代码并在HSM中运行,在我开始之前,我想看看是否有办法使用通用PKCS/JCE/CNG API来安全地执行此操作。

如果您只需要在不同的密钥下重新加密相同的密码,您可以使用
C_-Unwrap
创建一个具有已翻译机密值的临时HSM对象,然后使用
C_-Wrap
为所有收件人加密此临时HSM对象的值

这样,秘密永远不会离开HSM

类似这样的内容(经验证正在使用RSA-OAEP在SafeNet Luna 7上工作):


祝你好运

我想你可以用钥匙包装。使用发件人的私钥打开每封邮件的对称密钥:您获得对称密钥的句柄,而不是对称密钥本身,然后将其与下一个收件人的公钥打包。某些HSM提供翻译数据功能,您可以在其中进行翻译(使用密钥1解密,使用密钥2加密)从传入数据键1到传出密钥键2的数据,操作发生在HSM内部,因此您不会真正接触到清晰的数据,但这些命令看起来仅使用对称密钥,在这种情况下,您必须为对称数据密钥设置密钥交换机制…我为发送方生成了一个密钥对。。。那么,游戏结束了,你可以读取他们所有的消息。AFAIK没有一个通用的加密API支持安全的重新加密。顺便说一句,我几个月前就回答了。@JamesKPolk是的,但是发送者给了我很多钱,让我将消息安全地散播到成千上万台我正在管理其公钥的设备上。他们相信我做得对,这就是为什么他们用我给他们的公钥加密了它。我正在努力确保有效负载到达所有目的地,而我、我的团队、员工或黑客都无法看到它。我担心此解决方案无法满足OP的要求,“在我的应用程序内存附近没有解密的消息”。@jariq Why——解密的消息作为通用密钥存在于HSM中。应用程序只有此密钥的句柄。鉴于此通用密钥的模板是敏感的…应用程序对该密钥所做的只是将其包装为“收件人”(无论他们是谁)的公钥…很抱歉,我没有注意到您使用的是通用密钥。这是一个非常有趣的想法,值得探索!现在我想知道通用密钥值的大小限制是多少。@jariq我从未尝试过,但Luna 7声称支持生成(通过CKM_generic_SECRET_key_GEN)最多512字节长的通用密钥。还请注意,包裹/展开关键点没有多零件变体。
// 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);