Java 在Android中以AES-ECDH-MAC格式解密来自ATMEL的消息
我需要读取一条加密信息,它是从一个装有ATMEL芯片的设备上发送的 通信流程附于此处: 我做了所有关于套接字通信和ECDSA签名验证的事情。 现在我被困在解密阶段。 示例解密所需的数据如下所示:Java 在Android中以AES-ECDH-MAC格式解密来自ATMEL的消息,java,android,encryption,cryptography,atmel,Java,Android,Encryption,Cryptography,Atmel,我需要读取一条加密信息,它是从一个装有ATMEL芯片的设备上发送的 通信流程附于此处: 我做了所有关于套接字通信和ECDSA签名验证的事情。 现在我被困在解密阶段。 示例解密所需的数据如下所示: // 0 - private key (prv-h, android host) : "308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104206cb80a311272dae8a6bf01273c865a7d289
// 0 - private key (prv-h, android host) : "308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104206cb80a311272dae8a6bf01273c865a7d2890c16436330b88cb53d2bc55133f23a00a06082a8648ce3d030107a144034200046342f6b12beab7dd829bb95cee5073c8968e1cb406c185ab6dfd8889df0aec1f7ed1a31af57a0df00454cd683d83ee490e6747adbb6d6d68ab345149e7de1366"
// 1 / public ephemereal key (device pub-x): "04F0442494445A67606873A943F228A11FEE28B56502B3753E1FD4B5A369BA62B9DF0965C27E069E4997893CDBCC06B72A39907632FF6E4740597970F3DBEC9A17"
// 2 / encrypted message: "5A92B516C7F6C29168879D913F4D6210EC689419C16B67FB17365CB8C2363D80" "C263D7389158EB0ADF4470FC689CA6726F87EC82C3DCEAE49005C90230034DF7" (2 blocks of 64 bytes. I still don't know if i can collate them or decrypt one by one)
// 3 / iv (generated by device and sent) : "28395B5C43A82E3951B153A33B10B01C"
// 4 / randNum1 (generated by android and previously sent to device): "9f7ed0f97069b01b097f1e6b7e28465678a0b7cd45cfb354de0632b308879f94"
我尝试使用此处找到的流进行解密:
但我发现了一些不同之处,总的来说是先验证后解密,而我需要一个解密后mac的解决方案
此外,该解决方案依赖于我认为我没有的“标签”
而且,该解决方案不使用以前由主机发送的randNum
目前,我可以做到:
public static String DeCrypt(String privateKey_s, String ephemeralPublicKey_s, String message_s, String tag_s, String iv_s, String randNum1_s) throws Exception {
// premasterkey = ecdh(private, public)
PrivateKey privateKey = FromHexStringToPrivateKey(privateKey_s);
PublicKey ephemeralPublicKey = FromCompactStringToPublicKey(ephemeralPublicKey_s);
KeyAgreement ka = KeyAgreement.getInstance("ECDH");
ka.init(privateKey);
ka.doPhase(ephemeralPublicKey, true);
byte[] preMasterKey = ka.generateSecret();
在这里,我得到一个16字节(32个十六进制字符)的preMasterKey。我认为这是正确的。但是
从这一点上说,我不知道如何做好。我看到参考代码将公钥与共享密钥(preMasterKey)混合以获得会话密钥(加密密钥),但我的流程要求会话密钥从randNum1和preMasterKey派生
byte[] randNum1 = hexStringToByteArray(randNum1_s);
byte[] message = hexStringToByteArray(message_s);
byte[] iv = hexStringToByteArray(iv_s);
// Deriving encryption and mac keys.
HKDFBytesGenerator hkdfBytesGenerator = new HKDFBytesGenerator(new SHA256Digest());
byte[] khdfInput = ByteUtils.concatenate(randNum1, preMasterKey);
hkdfBytesGenerator.init(new HKDFParameters(khdfInput, null, "Android".getBytes(Charset.forName("UTF-8"))));
byte[] encryptionKey = new byte[16];
hkdfBytesGenerator.generateBytes(encryptionKey, 0, 16);
byte[] macKey = new byte[16];
hkdfBytesGenerator.generateBytes(macKey, 0, 16);
// Verifying Message Authentication Code (aka mac/tag)
Mac macGenerator = Mac.getInstance("HmacSHA256", "BC");
macGenerator.init(new SecretKeySpec(macKey, "HmacSHA256"));
byte[] expectedTag = macGenerator.doFinal(messaggio);
// if (!isArrayEqual(tag, expectedTag)) {
// throw new RuntimeException("Bad Message Authentication Code!");
// }
// Decrypting the message.
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
cipher.init(
Cipher.DECRYPT_MODE,
new SecretKeySpec(encryptionKey, "AES"),
new IvParameterSpec(iv));
return new String(cipher.doFinal(messaggio));
}
附录 也许我的私钥格式不正确 我通过这段代码生成了这对:
public String GenKeysHex() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
kpg.initialize(256);
KeyPair keyPair = kpg.generateKeyPair();
PrivateKey prv = keyPair.getPrivate();
PublicKey pub = keyPair.getPublic();
byte[] prvBytes = prv.getEncoded();
byte[] pubBytes = pub.getEncoded();
String result1 = new BigInteger(1, prvBytes).toString(16);
String result2 = new BigInteger(1, pubBytes).toString(16);
String result3 = FromLongToCompactPublic(result2);
return result3 + "," + result1 + "," + result2 ;
}
public static PrivateKey FromHexToPrivateKey(String Hex) throws Exception {
byte[] hardcodedPrivate = hexStringToByteArray(Hex);
PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(hardcodedPrivate);
KeyFactory factory = KeyFactory.getInstance("EC");
PrivateKey privateKey = factory.generatePrivate(privateSpec);
return privateKey;
}
public static String FromPrivateKeyToHex(PrivateKey key) throws Exception {
byte[] prvBytes = key.getEncoded();
String result1 = new BigInteger(1, prvBytes).toString(16);
return result1;
}
这是因为我需要创建一个库,并且我需要以字符串格式交换导入/导出数据,所以我检查了私钥的文本/十六进制格式是否通过其他两个例程保持一致
我想知道如何以更紧凑的形式获取私钥
方案中的MAC根本不用于消息身份验证,它只是用作KDF(密钥派生函数)。它派生加密密钥和用于设备实体身份验证的值(
DevMacCalc
)。虽然您可以从链接的代码中借用一些东西,例如算法实例化和初始化,但它不应该作为解密例程的起点。非常感谢。我完全卡住了。芯片是ATEC508A,我找不到任何东西可以告诉我如何从MAC(randNum1,preMasterKey)获取sessionKey。我完全不知道加密技术和Java。我只是一个“算法积分器”。我试着四处搜索,但我找不到任何在两个异构系统之间结合ECDH、MAC和AES通信的东西。你能告诉我什么地方吗?MAC输出的(最左边的)字节直接用作键或值来比较KDF结构。我对从事这类服务的人员不是很了解。我几乎不用思考就可以做到,但我没有所需的公司/时间等。除了其他问题,您的私钥看起来很长……这是因为(经过一点调查)它实际上是一个DER编码的公钥,而不是私钥。因此,即使我们能够计算出密钥派生应该如何工作,这里也没有足够的信息来解密任何东西,我们有两个公钥,而不是私钥和公钥。您方案中的MAC根本不用于消息身份验证,它只是用作KDF(密钥派生函数)。它派生加密密钥和用于设备实体身份验证的值(DevMacCalc
)。虽然您可以从链接的代码中借用一些东西,例如算法实例化和初始化,但它不应该作为解密例程的起点。非常感谢。我完全卡住了。芯片是ATEC508A,我找不到任何东西可以告诉我如何从MAC(randNum1,preMasterKey)获取sessionKey。我完全不知道加密技术和Java。我只是一个“算法积分器”。我试着四处搜索,但我找不到任何在两个异构系统之间结合ECDH、MAC和AES通信的东西。你能告诉我什么地方吗?MAC输出的(最左边的)字节直接用作键或值来比较KDF结构。我对从事这类服务的人员不是很了解。我几乎不用思考就可以做到,但我没有所需的公司/时间等。除了其他问题,您的私钥看起来很长……这是因为(经过一点调查)它实际上是一个DER编码的公钥,而不是私钥。因此,即使我们能够计算出密钥派生应该如何工作,这里也没有足够的信息来解密任何东西,我们有两个公钥,而不是一个私钥和一个公钥。