From 86461ada1a02ee4bb9d973cd69ca3575b6eb78a5 Mon Sep 17 00:00:00 2001 From: Damien 'Psolyca' Gaignon Date: Mon, 29 Jan 2024 21:51:45 +0100 Subject: [PATCH] [Huawei] Add new Crypto and authMode --- .../devices/huawei/HuaweiCrypto.java | 30 +++++++++++-------- .../devices/huawei/HuaweiPacket.java | 9 ++++++ .../devices/huawei/packets/DeviceConfig.java | 7 ++--- .../devices/huawei/HuaweiSupportProvider.java | 2 +- .../huawei/requests/GetAuthRequest.java | 23 +++++++------- .../huawei/requests/GetLinkParamsRequest.java | 2 ++ 6 files changed, 42 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCrypto.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCrypto.java index 0be828c01..08ef0a60f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCrypto.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCrypto.java @@ -24,6 +24,7 @@ import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.InvalidKeyException; import java.security.SecureRandom; +import java.security.spec.InvalidKeySpecException; import java.util.Arrays; import javax.crypto.BadPaddingException; @@ -78,15 +79,17 @@ public class HuaweiCrypto { public static final long ENCRYPTION_COUNTER_MAX = 0xFFFFFFFF; protected int authVersion; - protected boolean isHiChainLite = false; + protected int authMode; + protected byte authAlgo; public HuaweiCrypto(int authVersion) { this.authVersion = authVersion; } - public HuaweiCrypto(int authVersion, boolean isHiChainLite) { + public HuaweiCrypto(int authVersion, byte authAlgo, int authMode) { this(authVersion); - this.isHiChainLite = isHiChainLite; + this.authMode = authMode; + this.authAlgo = authAlgo; } public static byte[] generateNonce() { @@ -115,26 +118,27 @@ public class HuaweiCrypto { return CryptoUtils.calcHmacSha256(digestStep1, nonce); } - public byte[] computeDigestHiChainLite(byte[] message, byte[] key, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException { + public byte[] computeDigestHiChainLite(byte[] message, byte[] key, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException { + byte[] digestStep1; byte[] hashKey = CryptoUtils.digest(key); byte[] digestSecret = getDigestSecret(); for (int i = 0; i < digestSecret.length; i++) { digestSecret[i] = (byte) (((0xFF & hashKey[i]) ^ (digestSecret[i] & 0xFF)) & 0xFF); } - // 2 possibilities: - // - type 1 : Pbk (SDK_INT>= 0x17) fallback to MacSha - // - type 2 : MacSha - // We force type 2 to avoid a new calculation byte[] msgToDigest = ByteBuffer.allocate(18) .put(digestSecret) .put(message) .array(); - byte[] digestStep1 = CryptoUtils.calcHmacSha256(msgToDigest, nonce) ; + if (authAlgo == 0x01) { + digestStep1 = CryptoUtils.pbkdf2Sha256(msgToDigest, nonce, 0x3e8, 0x100); + } else { + digestStep1 = CryptoUtils.calcHmacSha256(msgToDigest, nonce); + } return CryptoUtils.calcHmacSha256(digestStep1, nonce); } - public byte[] digestChallenge(byte[] secretKey, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException { - if (isHiChainLite) { + public byte[] digestChallenge(byte[] secretKey, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException { + if (authMode == 0x02) { if (secretKey == null) return null; if (authVersion == 0x02) { @@ -149,8 +153,8 @@ public class HuaweiCrypto { return computeDigest(MESSAGE_CHALLENGE, nonce); } - public byte[] digestResponse(byte[] secretKey, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException { - if (isHiChainLite) { + public byte[] digestResponse(byte[] secretKey, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException { + if (authMode == 0x02) { if (secretKey == null) return null; if (authVersion == 0x02) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java index 6df377190..a16c913d1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java @@ -55,6 +55,7 @@ public class HuaweiPacket { protected byte[] pinCode = null; protected byte interval; + protected byte authAlgo; public void setAuthVersion(byte authVersion) { this.authVersion = authVersion; @@ -134,6 +135,14 @@ public class HuaweiPacket { public void setEncryptionCounter(long counter) { this.encryptionCounter = counter; } + + public void setAuthAlgo(byte authAlgo) { + this.authAlgo = authAlgo; + } + + public byte getAuthAlgo () { + return this.authAlgo; + } } public static abstract class ParseException extends Exception { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/DeviceConfig.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/DeviceConfig.java index fb88dda3e..cba02d042 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/DeviceConfig.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/packets/DeviceConfig.java @@ -625,8 +625,7 @@ public class DeviceConfig { public Request( ParamsProvider paramsProvider, byte[] challenge, - byte[] nonce, - boolean isHiChainLite + byte[] nonce ) { super(paramsProvider); @@ -636,8 +635,8 @@ public class DeviceConfig { this.tlv = new HuaweiTLV() .put(0x01, challenge) .put(0x02, nonce); - if (isHiChainLite) - this.tlv.put(0x03, (byte)0x02); // Force type 2 + if (paramsProvider.getAuthMode() == 0x02) + this.tlv.put(0x03, paramsProvider.getAuthAlgo()); this.isEncrypted = false; this.complete = true; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java index 486698d14..eed8a0a7d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java @@ -376,7 +376,7 @@ public class HuaweiSupportProvider { protected void initializeDeviceHiChainLiteMode(Request linkParamsReq) { try { createSecretKey(); - GetAuthRequest authReq = new GetAuthRequest(this, linkParamsReq, true); + GetAuthRequest authReq = new GetAuthRequest(this, linkParamsReq); GetBondParamsRequest bondParamsReq = new GetBondParamsRequest(this); GetBondRequest bondReq = new GetBondRequest(this); authReq.nextRequest(bondParamsReq); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetAuthRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetAuthRequest.java index 8d1a4a274..e4a98141a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetAuthRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetAuthRequest.java @@ -22,6 +22,7 @@ import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; import java.util.Arrays; import java.util.List; @@ -36,9 +37,10 @@ public class GetAuthRequest extends Request { protected final byte[] clientNonce; protected short authVersion; - protected boolean isHiChainLite = false; + protected byte authAlgo; protected byte[] doubleNonce; protected byte[] key = null; + protected byte authMode; public GetAuthRequest(HuaweiSupportProvider support, Request linkParamsReq) { @@ -51,22 +53,17 @@ public class GetAuthRequest extends Request { .put(clientNonce) .array(); this.authVersion = paramsProvider.getAuthVersion(); - } - - public GetAuthRequest(HuaweiSupportProvider support, - Request linkParamsReq, - boolean isHiChainLite) { - this(support, linkParamsReq); - this.isHiChainLite = isHiChainLite; + this.authAlgo = paramsProvider.getAuthAlgo(); + this.authMode = paramsProvider.getAuthMode(); } @Override protected List createRequest() throws RequestCreationException { - huaweiCrypto = new HuaweiCrypto(authVersion, isHiChainLite); + huaweiCrypto = new HuaweiCrypto(authVersion, authAlgo, authMode); byte[] nonce; try { - if (isHiChainLite) { + if (authMode == 0x02) { key = paramsProvider.getPinCode(); if (authVersion == 0x02) key = paramsProvider.getSecretKey(); @@ -78,10 +75,10 @@ public class GetAuthRequest extends Request { byte[] challenge = huaweiCrypto.digestChallenge(key, doubleNonce); if (challenge == null) throw new RequestCreationException("Challenge null"); - return new DeviceConfig.Auth.Request(paramsProvider, challenge, nonce, isHiChainLite).serialize(); + return new DeviceConfig.Auth.Request(paramsProvider, challenge, nonce).serialize(); } catch (HuaweiPacket.CryptoException e) { throw new RequestCreationException(e); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { + } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException e) { throw new RequestCreationException("Digest exception", e); } } @@ -105,7 +102,7 @@ public class GetAuthRequest extends Request { + StringUtils.bytesToHex(expectedAnswer) ); } - } catch (NoSuchAlgorithmException | InvalidKeyException e) { + } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException e) { throw new ResponseParseException("Challenge response digest exception"); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetLinkParamsRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetLinkParamsRequest.java index 9c7ff95ba..8c135eb86 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetLinkParamsRequest.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetLinkParamsRequest.java @@ -82,5 +82,7 @@ public class GetLinkParamsRequest extends Request { paramsProvider.setAuthVersion(((LinkParams.Response) receivedPacket).authVersion); this.bondState = ((LinkParams.Response) receivedPacket).bondState; + + paramsProvider.setAuthAlgo(((LinkParams.Response) receivedPacket).authAlgo); } }