1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-06-27 23:40:31 +02:00

[Huawei] Add new Crypto and authMode

This commit is contained in:
Damien 'Psolyca' Gaignon 2024-01-29 21:51:45 +01:00
parent f759072a7c
commit 86461ada1a
No known key found for this signature in database
GPG Key ID: 9E9404E5D9E11843
6 changed files with 42 additions and 31 deletions

View File

@ -24,6 +24,7 @@ import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays; import java.util.Arrays;
import javax.crypto.BadPaddingException; import javax.crypto.BadPaddingException;
@ -78,15 +79,17 @@ public class HuaweiCrypto {
public static final long ENCRYPTION_COUNTER_MAX = 0xFFFFFFFF; public static final long ENCRYPTION_COUNTER_MAX = 0xFFFFFFFF;
protected int authVersion; protected int authVersion;
protected boolean isHiChainLite = false; protected int authMode;
protected byte authAlgo;
public HuaweiCrypto(int authVersion) { public HuaweiCrypto(int authVersion) {
this.authVersion = authVersion; this.authVersion = authVersion;
} }
public HuaweiCrypto(int authVersion, boolean isHiChainLite) { public HuaweiCrypto(int authVersion, byte authAlgo, int authMode) {
this(authVersion); this(authVersion);
this.isHiChainLite = isHiChainLite; this.authMode = authMode;
this.authAlgo = authAlgo;
} }
public static byte[] generateNonce() { public static byte[] generateNonce() {
@ -115,26 +118,27 @@ public class HuaweiCrypto {
return CryptoUtils.calcHmacSha256(digestStep1, nonce); 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[] hashKey = CryptoUtils.digest(key);
byte[] digestSecret = getDigestSecret(); byte[] digestSecret = getDigestSecret();
for (int i = 0; i < digestSecret.length; i++) { for (int i = 0; i < digestSecret.length; i++) {
digestSecret[i] = (byte) (((0xFF & hashKey[i]) ^ (digestSecret[i] & 0xFF)) & 0xFF); 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) byte[] msgToDigest = ByteBuffer.allocate(18)
.put(digestSecret) .put(digestSecret)
.put(message) .put(message)
.array(); .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); return CryptoUtils.calcHmacSha256(digestStep1, nonce);
} }
public byte[] digestChallenge(byte[] secretKey, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException { public byte[] digestChallenge(byte[] secretKey, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException {
if (isHiChainLite) { if (authMode == 0x02) {
if (secretKey == null) if (secretKey == null)
return null; return null;
if (authVersion == 0x02) { if (authVersion == 0x02) {
@ -149,8 +153,8 @@ public class HuaweiCrypto {
return computeDigest(MESSAGE_CHALLENGE, nonce); return computeDigest(MESSAGE_CHALLENGE, nonce);
} }
public byte[] digestResponse(byte[] secretKey, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException { public byte[] digestResponse(byte[] secretKey, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException {
if (isHiChainLite) { if (authMode == 0x02) {
if (secretKey == null) if (secretKey == null)
return null; return null;
if (authVersion == 0x02) { if (authVersion == 0x02) {

View File

@ -55,6 +55,7 @@ public class HuaweiPacket {
protected byte[] pinCode = null; protected byte[] pinCode = null;
protected byte interval; protected byte interval;
protected byte authAlgo;
public void setAuthVersion(byte authVersion) { public void setAuthVersion(byte authVersion) {
this.authVersion = authVersion; this.authVersion = authVersion;
@ -134,6 +135,14 @@ public class HuaweiPacket {
public void setEncryptionCounter(long counter) { public void setEncryptionCounter(long counter) {
this.encryptionCounter = 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 { public static abstract class ParseException extends Exception {

View File

@ -625,8 +625,7 @@ public class DeviceConfig {
public Request( public Request(
ParamsProvider paramsProvider, ParamsProvider paramsProvider,
byte[] challenge, byte[] challenge,
byte[] nonce, byte[] nonce
boolean isHiChainLite
) { ) {
super(paramsProvider); super(paramsProvider);
@ -636,8 +635,8 @@ public class DeviceConfig {
this.tlv = new HuaweiTLV() this.tlv = new HuaweiTLV()
.put(0x01, challenge) .put(0x01, challenge)
.put(0x02, nonce); .put(0x02, nonce);
if (isHiChainLite) if (paramsProvider.getAuthMode() == 0x02)
this.tlv.put(0x03, (byte)0x02); // Force type 2 this.tlv.put(0x03, paramsProvider.getAuthAlgo());
this.isEncrypted = false; this.isEncrypted = false;
this.complete = true; this.complete = true;
} }

View File

@ -376,7 +376,7 @@ public class HuaweiSupportProvider {
protected void initializeDeviceHiChainLiteMode(Request linkParamsReq) { protected void initializeDeviceHiChainLiteMode(Request linkParamsReq) {
try { try {
createSecretKey(); createSecretKey();
GetAuthRequest authReq = new GetAuthRequest(this, linkParamsReq, true); GetAuthRequest authReq = new GetAuthRequest(this, linkParamsReq);
GetBondParamsRequest bondParamsReq = new GetBondParamsRequest(this); GetBondParamsRequest bondParamsReq = new GetBondParamsRequest(this);
GetBondRequest bondReq = new GetBondRequest(this); GetBondRequest bondReq = new GetBondRequest(this);
authReq.nextRequest(bondParamsReq); authReq.nextRequest(bondParamsReq);

View File

@ -22,6 +22,7 @@ import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -36,9 +37,10 @@ public class GetAuthRequest extends Request {
protected final byte[] clientNonce; protected final byte[] clientNonce;
protected short authVersion; protected short authVersion;
protected boolean isHiChainLite = false; protected byte authAlgo;
protected byte[] doubleNonce; protected byte[] doubleNonce;
protected byte[] key = null; protected byte[] key = null;
protected byte authMode;
public GetAuthRequest(HuaweiSupportProvider support, public GetAuthRequest(HuaweiSupportProvider support,
Request linkParamsReq) { Request linkParamsReq) {
@ -51,22 +53,17 @@ public class GetAuthRequest extends Request {
.put(clientNonce) .put(clientNonce)
.array(); .array();
this.authVersion = paramsProvider.getAuthVersion(); this.authVersion = paramsProvider.getAuthVersion();
} this.authAlgo = paramsProvider.getAuthAlgo();
this.authMode = paramsProvider.getAuthMode();
public GetAuthRequest(HuaweiSupportProvider support,
Request linkParamsReq,
boolean isHiChainLite) {
this(support, linkParamsReq);
this.isHiChainLite = isHiChainLite;
} }
@Override @Override
protected List<byte[]> createRequest() throws RequestCreationException { protected List<byte[]> createRequest() throws RequestCreationException {
huaweiCrypto = new HuaweiCrypto(authVersion, isHiChainLite); huaweiCrypto = new HuaweiCrypto(authVersion, authAlgo, authMode);
byte[] nonce; byte[] nonce;
try { try {
if (isHiChainLite) { if (authMode == 0x02) {
key = paramsProvider.getPinCode(); key = paramsProvider.getPinCode();
if (authVersion == 0x02) if (authVersion == 0x02)
key = paramsProvider.getSecretKey(); key = paramsProvider.getSecretKey();
@ -78,10 +75,10 @@ public class GetAuthRequest extends Request {
byte[] challenge = huaweiCrypto.digestChallenge(key, doubleNonce); byte[] challenge = huaweiCrypto.digestChallenge(key, doubleNonce);
if (challenge == null) if (challenge == null)
throw new RequestCreationException("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) { } catch (HuaweiPacket.CryptoException e) {
throw new RequestCreationException(e); throw new RequestCreationException(e);
} catch (NoSuchAlgorithmException | InvalidKeyException e) { } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException e) {
throw new RequestCreationException("Digest exception", e); throw new RequestCreationException("Digest exception", e);
} }
} }
@ -105,7 +102,7 @@ public class GetAuthRequest extends Request {
+ StringUtils.bytesToHex(expectedAnswer) + StringUtils.bytesToHex(expectedAnswer)
); );
} }
} catch (NoSuchAlgorithmException | InvalidKeyException e) { } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException e) {
throw new ResponseParseException("Challenge response digest exception"); throw new ResponseParseException("Challenge response digest exception");
} }
} }

View File

@ -82,5 +82,7 @@ public class GetLinkParamsRequest extends Request {
paramsProvider.setAuthVersion(((LinkParams.Response) receivedPacket).authVersion); paramsProvider.setAuthVersion(((LinkParams.Response) receivedPacket).authVersion);
this.bondState = ((LinkParams.Response) receivedPacket).bondState; this.bondState = ((LinkParams.Response) receivedPacket).bondState;
paramsProvider.setAuthAlgo(((LinkParams.Response) receivedPacket).authAlgo);
} }
} }