使用 HKDF 密钥进行 Crypto-js 加密和 Python 解密

3

根据此处提供的示例,可以建立在JS(Crypto-JS)和Python之间共享秘密和派生键。这样就可以在两端获得相同的共享秘密和派生键。

但是,当我尝试以下加密时,我无法找到从Python正确解密的方法。我的理解是可能我可能搞错了填充或盐和哈希值。

    const payload = "hello"
    var iv = CryptoJS.enc.Utf8.parse("1020304050607080");

    var test = CryptoJS.AES.encrypt(
        payload,
        derived_key,
        {iv: iv, mode: CryptoJS.mode.CBC}
    ).toString();

    console.log(test)

输出 "y+In4kriw0qy4lji6/x14g=="

Python(其中之一的尝试):

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad,unpad

iv = "1020304050607080"

test_enc = "y+In4kriw0qy4lji6/x14g=="
enc = base64.b64decode(test_enc)

cipher = AES.new(derived_key, AES.MODE_CBC, iv.encode('utf-8'))

print(base64.b64decode(cipher.decrypt(enc)))

print(unpad(cipher.decrypt(enc),16))

我已经使用密码实现了加密,但在HKDF方面遇到了困难,非常感谢您的任何指导。

编辑:

以下是完整的Python代码:

from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
import base64


from Crypto.Cipher import AES
from Crypto.Util.Padding import pad,unpad


def deriveKey():

  server_pkcs8 = b'''-----BEGIN PRIVATE KEY-----
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBReGpDVmoVTzxNbJx6
aL4L9z1EdB91eonAmAw7mKDocLfCJITXZPUAmM46c6AipTmhZANiAAR3t96P0ZhU
jtW3rHkHpeGu4e+YT+ufMiMeanE/w8p+d9aCslvIbZyBBzeZ/266yqTUUoiYDzqv
Hb5q8rz7vEgr3DG4XfHYpCqfE2nttQGK3emHKGnvY239AteZkdwMpcs=
-----END PRIVATE KEY-----'''

  client_x509 = b'''-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm0xeyy3nVnYpOpx/CV/FnlNEdWUZaqtB
AGf7flKxXEjmlSUjseYzCd566sLpNg56Gw6hcFx+rWTLGR4eDRWfmwlXhyUasuEg
mb0BQf8XJLBdvadb9eFx2CP1yjBsiy8e
-----END PUBLIC KEY-----'''

  client_public_key = serialization.load_pem_public_key(client_x509)
  server_private_key = serialization.load_pem_private_key(server_pkcs8, password=None)
  shared_secret = server_private_key.exchange(ec.ECDH(), client_public_key)
  print('Shared secret: ' + base64.b64encode(shared_secret).decode('utf8')) # Shared secret: xbU6oDHMTYj3O71liM5KEJof3/0P4HlHJ28k7qtdqU/36llCizIlOWXtj8v+IngF

  salt_bytes = "12345678".encode('utf-8')
  info_bytes = "abc".encode('utf-8')

  derived_key = HKDF(
    algorithm=hashes.SHA256(),
    length=32,
    salt=salt_bytes,
    info=info_bytes,
  ).derive(shared_secret)
  print('Derived key:   ' + base64.b64encode(derived_key).decode('utf8'))
  return derived_key

derived_key = deriveKey()
iv = "1020304050607080"

test_enc = "y+In4kriw0qy4lji6/x14g=="
enc = base64.b64decode(test_enc)

cipher = AES.new(derived_key, AES.MODE_CBC, iv.encode('utf-8'))

print(base64.b64decode(cipher.decrypt(enc)))

print(unpad(cipher.decrypt(enc),16))

1
Python代码中的第一个print()应该被删除,因为明文不是Base64编码的。除此之外,第二个print()提供了使用我的测试密钥进行正确解密的结果。然而,由于您没有指定derived_key,所以无法进行完全重现。也许您在CryptoJS代码中使用了错误的编码器。因此,您应该发布您的密钥以及如何解析此密钥。 - Topaco
我刚刚编辑了问题,提供了完整的代码。@Topaco - Waelmas
仍未完成。在CryptoJS代码中,如何为derived_key分配值?这个部分缺失了!这可能是错误的根源,因为即使使用您的密钥,我也无法重现问题。 - Topaco
1
长话短说:在删除第一个“print()”后,您的Python代码返回了“derived_key”的Base64编码:“LefjQ2pEXmiy/nNZvEJ43i8hJuaAnzbA1Cbn1hOuAgA =”。因此,在CryptoJS代码中,必须应用“var derived_key = CryptoJS.enc.Base64.parse('LefjQ2pEXmiy / nNZvEJ43i8hJuaAnzbA1Cbn1hOuAgA =')”。因此,CryptoJS代码对于您的明文和IV返回密文:“bLdmGA + HLLyFEVtBEuCzVg ==”,然后可以使用“test_enc =“ bLdmGA + HLLyFEVtBEuCzVg ==” Python代码成功解密。 - Topaco
问题实际上是我将密钥以其原始格式传递给了CryptoJS。非常感谢。你的回答总是很到位。 (请随意将其作为答案添加,以便我可以将其标记为正确答案) - Waelmas
不客气。我将我的评论发布为答案。 - Topaco
1个回答

2
问题在于CryptoJS代码中的密钥未正确传递。
发布的Python代码生成Base64编码键LefjQ2pEXmiy/nNZvEJ43i8hJuaAnzbA1Cbn1hOuAgA=。必须使用Base64编码器将其导入CryptoJS代码:

const payload = "hello"
var derived_key = CryptoJS.enc.Base64.parse("LefjQ2pEXmiy/nNZvEJ43i8hJuaAnzbA1Cbn1hOuAgA=")
var iv = CryptoJS.enc.Utf8.parse("1020304050607080");
var test = CryptoJS.AES.encrypt(payload, derived_key, {iv: iv, mode: CryptoJS.mode.CBC}).toString();
document.getElementById("ct").innerHTML = test; // bLdmGA+HLLyFEVtBEuCzVg==
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
<p style="font-family:'Courier New', monospace;" id="ct"></p>

这里生成的密文bLdmGA+HLLyFEVtBEuCzVg==可以使用以下Python代码进行解密:

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import base64

test_enc = "bLdmGA+HLLyFEVtBEuCzVg=="
enc = base64.b64decode(test_enc)
derived_key = base64.b64decode("LefjQ2pEXmiy/nNZvEJ43i8hJuaAnzbA1Cbn1hOuAgA=")
iv = "1020304050607080"
cipher = AES.new(derived_key, AES.MODE_CBC, iv.encode('utf-8'))
print(unpad(cipher.decrypt(enc),16)) # b'hello'

请注意,出于安全原因,不应使用静态IV,以避免重复使用密钥/IV对。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接