TLS Master Secret 用于在 X25519 上生成 Secret [关闭]

问题描述 投票:0回答:0

我正在尝试对使用 X25519 算法的密钥推导生成的密码进行密文解密。虽然我能够使用 Java 系统中生成的私钥进行解密,但它在 python 上失败了。 Java 代码使用 generate secret 和 tlspremaster,这是我在 python 上找不到的东西。有人可以建议如何解决吗?我会在这里发布我的代码。

我对密码学还很陌生,还在学习。

下面是我的代码。 pkey 是我在 Mac 主机上本地生成的私钥。密钥交换后,我将派生一个对称密钥来解密从 Java 收到的加密字符串。这些密钥是在我的 Mac 主机上生成的 X25519 密钥,其他系统的公钥以 DER 编码格式返回。在 Java 中使用我的公钥和远程私钥解密相同的有效负载效果很好。然而,同样的反过来是行不通的。我在下面做错了什么?

    from cryptography.hazmat.primitives import serialization
    import base64
    from cryptography.hazmat.primitives.ciphers import         Cipher,algorithms,modes
    from cryptography.hazmat.primitives import hashes
    from cryptography.hazmat.primitives.kdf.hkdf import HKDF

    pkey = serialization.load_der_private_key(
    base64.b64decode("MC4CAQAwBQYDK2VuBCIEIKh1Dq7Fu82lqQdBQJTHTvBTxtD6hLconopqvVLVy81s"),
password=None

)

    ukey=pkey.public_key()
    encstr = base64.b64decode("tAIfdjkAClrwWFcKVYMiCYVhm7NFAotPyBgF2YJkM2ETWPEYcGG6g37MivEhS8b5".encode('utf-8'))


    uenkey = ukey.public_bytes(
    encoding=serialization.Encoding.DER,
    format=serialization.PublicFormat.SubjectPublicKeyInfo
     )

    penkey = pkey.private_bytes(
      encoding=serialization.Encoding.DER,
    format=serialization.PrivateFormat.PKCS8,
      encryption_algorithm=serialization.NoEncryption()
    )
    ondcpub = (base64.b64decode("MCowBQYDK2VuAyEAa9Wbpvd9SsrpOZFcynyt/TO3x0Yrqyys4NUGIvyxX2Q="))
    oenkey = serialization.load_der_public_key(ondcpub)
    shared_key = pkey.exchange(oenkey)
    shkey = base64.urlsafe_b64encode(shared_key).decode('utf-8')
    print("Shared Secret: ",      base64.b64encode(shared_key).decode('utf-8'))

     hkdf = HKDF(
     algorithm=hashes.BLAKE2b(64),
     length=32,
     salt=None,
     info=None
     )

     key = hkdf.derive(shared_key)

     print("Derived Secret: ", base64.b64encode(key).decode('utf-8'))

     iv = encstr[0:16]
     cipher = Cipher(algorithms.AES(key), modes.CBC(iv))

     dec = cipher.decryptor()

     text = dec.update(encstr) + dec.finalize()

但是,在打印文本时,我返回的是垃圾字节,而不是我加密的内容。

下面是能够正确解密字符串而没有问题的 Java 代码:

import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
//
import org.springframework.stereotype.Component;

import lombok.Data;

@Component
@Data
public class SubscribeEncryptDecrypt {

String clientPrivateKey = "MFECAQEwBQYDK2VuBCIEIChY69PwPeovw1zAh7TRU+E40LIEykBsbIBp3CanVvRegSEASfWOME2kQQ75i5iMHx0ZodBn0P9UTHcOkeczDmeOVkU=";
String clientPublicKey = "MCowBQYDK2VuAyEASfWOME2kQQ75i5iMHx0ZodBn0P9UTHcOkeczDmeOVkU=";

String proteanPublicKey = "MCowBQYDK2VuAyEALtPj74XkIrkyxTqyssjtYJ3KRND5FnzK5MDrwlK3kC8=";
String proteanPrivateKey = "MFECAQEwBQYDK2VuBCIEIAj5U1DVAX5eGI1jIIcjmzWgPQlIg/T1Q6A3pZ0AIWp6gSEAJGnKRTAEcSvpgD0mw9gBHv94E3w8sTtmPlszuXIEAF0=";

public static String secretKey = "TlsPremasterSecret";

public static void setup() {
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(new BouncyCastleProvider());
}
}

public String decrypt(String clientPrivateKey, String proteanPublicKey, String value) {

try {
byte[] dataBytes = Base64.getDecoder().decode(proteanPublicKey);
PublicKey publicKey = getPublicKey("X25519", dataBytes);

dataBytes = Base64.getDecoder().decode(clientPrivateKey);
PrivateKey privateKey = getPrivateKey("X25519", dataBytes);

KeyAgreement atServer1 = KeyAgreement.getInstance("X25519", BouncyCastleProvider.PROVIDER_NAME);
atServer1.init(privateKey); // Server1 uses its private key to initialize the aggreement object
atServer1.doPhase(publicKey, true); // Uses Server2's ppublic Key
SecretKey key1 = atServer1.generateSecret(secretKey); // derive secret at server 1.
// "TlsPremasterSecret" is the algorithm for

Cipher cipher2 = Cipher.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
cipher2.init(Cipher.DECRYPT_MODE, key1); // Same derived key in server 2same as key1
byte[] decrypted2 = cipher2.doFinal(Base64.getDecoder().decode(value)); // b64 decode the
// message before

return new String(decrypted2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}

public PublicKey getPublicKey(String algo, byte[] jceBytes) throws Exception {
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(jceBytes);
PublicKey key = KeyFactory.getInstance(algo, BouncyCastleProvider.PROVIDER_NAME)
.generatePublic(x509EncodedKeySpec);
return key;
}

public PrivateKey getPrivateKey(String algo, byte[] jceBytes) throws Exception {
PrivateKey key = KeyFactory.getInstance(algo, BouncyCastleProvider.PROVIDER_NAME)
.generatePrivate(new PKCS8EncodedKeySpec(jceBytes));
return key;
}

public String encrypt(String clientPublicKey, String proteanPrivateKey, String value) {

try {
byte[] dataBytes = Base64.getDecoder().decode(clientPublicKey);
PublicKey publicKey = getPublicKey("X25519", dataBytes);

dataBytes = Base64.getDecoder().decode(proteanPrivateKey);
PrivateKey privateKey = getPrivateKey("X25519", dataBytes);

KeyAgreement atServer1 = KeyAgreement.getInstance("X25519", BouncyCastleProvider.PROVIDER_NAME);
atServer1.init(privateKey); // Server1 uses its private key to initialize the aggreement object
atServer1.doPhase(publicKey, true); // Uses Server2's ppublic Key
SecretKey key1 = atServer1.generateSecret(secretKey); // //derive secret at server 1.
// "TlsPremasterSecret" is the algorithm for

// *Server1
Cipher cipher1 = Cipher.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
cipher1.init(Cipher.ENCRYPT_MODE, key1);
byte[] encrypted1 = cipher1.doFinal(value.getBytes(StandardCharsets.UTF_8));
String b64Encryped1 = Base64.getEncoder().encodeToString(encrypted1);

return b64Encryped1;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}


public static void main(String[] args) {
SubscribeEncryptDecrypt decr = new SubscribeEncryptDecrypt();

decr.setup();
 
String enc = decr.encrypt("MCowBQYDK2VuAyEAr+B5vDW7a3QFkCcYqf3RMMi5BxsnwU3fy63pxpCDnQM=",
"MFECAQEwBQYDK2VuBCIEIJDIsJi4nLGZ7BKaJkkIzJxubIndEOvT5hx0MKgoGYFvgSEA13ZQjiRLAA5YG6prELnmQwboQlpj0MzI94XF/kG4UmY=",
"Fossgen is awesome!");
System.out.println("ENC:");
System.out.println(enc);
System.out.println("DECR3:");
System.out.println(decr.decrypt("MFECAQEwBQYDK2VuBCIEIEhk0BhCxAEIHg8HehKzo9IHmCFRpcp9IlBGYsWTPdVzgSEAMmKN2FKRf+ojfYYQ80ZcgyJQvQlbxDA8BAsxNG4vuGI=", 
"MCowBQYDK2VuAyEA13ZQjiRLAA5YG6prELnmQwboQlpj0MzI94XF/kG4UmY=",
enc));

}

}

代码中提到的键是真实的。

python cryptography diffie-hellman
© www.soinside.com 2019 - 2024. All rights reserved.