From 9ea9bd96bb9e9d5a7c68a42a7bbdb15c9fd2a192 Mon Sep 17 00:00:00 2001 From: dangfan Date: Wed, 21 Apr 2021 09:25:59 +0800 Subject: [PATCH 1/2] fix the compatibility of compressed and uncompressed format in ECDH --- .../operations/PsoDecryptTokenOp.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/operations/PsoDecryptTokenOp.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/operations/PsoDecryptTokenOp.java index 537c92b5a..649211493 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/operations/PsoDecryptTokenOp.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/operations/PsoDecryptTokenOp.java @@ -161,14 +161,23 @@ public class PsoDecryptTokenOp { */ byte[] keyEncryptionKey = response.getData(); - int xLen; - if (eckf.isX25519()) { - xLen = keyEncryptionKey.length; - } else { + /* From rfc6637#section-7 : + The input of KDF should be the x portion of the point. + As the result of ECDH can be expressed in two formats: compressed and uncompressed, + we have to deal with each case. + */ + int xLen, startPos; + if (keyEncryptionKey[0] == 0x04 && keyEncryptionKey.length % 2 == 1) { + // uncompressed format xLen = (keyEncryptionKey.length - 1) / 2; + startPos = 1; + } else { + // compressed format + xLen = keyEncryptionKey.length; + startPos = 0; } final byte[] kekX = new byte[xLen]; - System.arraycopy(keyEncryptionKey, eckf.isX25519() ? 0 : 1, kekX, 0, xLen); + System.arraycopy(keyEncryptionKey, startPos, kekX, 0, xLen); final byte[] keyEnc = new byte[encryptedSessionKeyMpi[mpiLength + 2]]; From ec5d5e399ff69a29e2a7d0736ad214019fec4087 Mon Sep 17 00:00:00 2001 From: dangfan Date: Wed, 21 Apr 2021 19:09:35 +0800 Subject: [PATCH 2/2] add more documentation of decryptSessionKeyEcdh --- .../keychain/securitytoken/operations/PsoDecryptTokenOp.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/operations/PsoDecryptTokenOp.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/operations/PsoDecryptTokenOp.java index 649211493..bbf975557 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/operations/PsoDecryptTokenOp.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/securitytoken/operations/PsoDecryptTokenOp.java @@ -164,7 +164,10 @@ public class PsoDecryptTokenOp { /* From rfc6637#section-7 : The input of KDF should be the x portion of the point. As the result of ECDH can be expressed in two formats: compressed and uncompressed, - we have to deal with each case. + we have to deal with each case: + An uncompressed point is encoded as 04 || x || y, with x and y are of the same size. + However, a valid x may be led with 04, so we have to also check the length of the result. + A compressed point, on the other hand, is encoded as x only. Therefore, we use the value directly. */ int xLen, startPos; if (keyEncryptionKey[0] == 0x04 && keyEncryptionKey.length % 2 == 1) {