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..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 @@ -161,14 +161,26 @@ 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: + 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) { + // 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]];