mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-25 03:16:51 +01:00
[Huawei] Fix pin code encoding
This commit is contained in:
parent
8aaa766dcd
commit
2880297c51
@ -17,7 +17,9 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.devices.huawei;
|
package nodomain.freeyourgadget.gadgetbridge.devices.huawei;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.CryptoUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.CryptoUtils;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
@ -100,13 +102,15 @@ public class HuaweiCrypto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private byte[] getDigestSecret() {
|
private byte[] getDigestSecret() {
|
||||||
|
byte[] digest;
|
||||||
if (authVersion == 1) {
|
if (authVersion == 1) {
|
||||||
return DIGEST_SECRET_v1;
|
digest = DIGEST_SECRET_v1.clone();
|
||||||
} else if (authVersion == 2) {
|
} else if (authVersion == 2) {
|
||||||
return DIGEST_SECRET_v2;
|
digest = DIGEST_SECRET_v2.clone();
|
||||||
} else {
|
} else {
|
||||||
return DIGEST_SECRET_v3;
|
digest = DIGEST_SECRET_v3.clone();
|
||||||
}
|
}
|
||||||
|
return digest;
|
||||||
}
|
}
|
||||||
public byte[] computeDigest(byte[] message, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException {
|
public byte[] computeDigest(byte[] message, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException {
|
||||||
byte[] digestSecret = getDigestSecret();
|
byte[] digestSecret = getDigestSecret();
|
||||||
@ -118,9 +122,9 @@ 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, InvalidKeySpecException {
|
public byte[] computeDigestHiChainLite(byte[] message, byte[] key, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException, UnsupportedEncodingException {
|
||||||
byte[] digestStep1;
|
byte[] digestStep1;
|
||||||
byte[] hashKey = CryptoUtils.digest(key);
|
byte[] hashKey = CryptoUtils.digest(GB.hexdump(key).getBytes("UTF-8"));
|
||||||
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);
|
||||||
@ -130,14 +134,14 @@ public class HuaweiCrypto {
|
|||||||
.put(message)
|
.put(message)
|
||||||
.array();
|
.array();
|
||||||
if (authAlgo == 0x01) {
|
if (authAlgo == 0x01) {
|
||||||
digestStep1 = CryptoUtils.pbkdf2Sha256(msgToDigest, nonce, 0x3e8, 0x100);
|
digestStep1 = CryptoUtils.pbkdf2Sha256(GB.hexdump(msgToDigest), GB.hexdump(nonce), 0x3e8, 0x100);
|
||||||
} else {
|
} else {
|
||||||
digestStep1 = CryptoUtils.calcHmacSha256(msgToDigest, nonce);
|
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, InvalidKeySpecException {
|
public byte[] digestChallenge(byte[] secretKey, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException, UnsupportedEncodingException {
|
||||||
if (authMode == 0x02) {
|
if (authMode == 0x02) {
|
||||||
if (secretKey == null)
|
if (secretKey == null)
|
||||||
return null;
|
return null;
|
||||||
@ -153,7 +157,7 @@ public class HuaweiCrypto {
|
|||||||
return computeDigest(MESSAGE_CHALLENGE, nonce);
|
return computeDigest(MESSAGE_CHALLENGE, nonce);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] digestResponse(byte[] secretKey, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException {
|
public byte[] digestResponse(byte[] secretKey, byte[] nonce) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException, UnsupportedEncodingException {
|
||||||
if (authMode == 0x02) {
|
if (authMode == 0x02) {
|
||||||
if (secretKey == null)
|
if (secretKey == null)
|
||||||
return null;
|
return null;
|
||||||
@ -216,9 +220,11 @@ public class HuaweiCrypto {
|
|||||||
return CryptoUtils.decryptAES_CBC_Pad(data, encryptionKey, iv);
|
return CryptoUtils.decryptAES_CBC_Pad(data, encryptionKey, iv);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] decryptPinCode(byte[] message, byte[] iv) throws CryptoException {
|
public byte[] decryptPinCode(byte encryptMethod, byte[] message, byte[] iv) throws CryptoException {
|
||||||
byte[] secretKey = getDigestSecret();
|
byte[] secretKey = getDigestSecret();
|
||||||
try {
|
try {
|
||||||
|
if (encryptMethod == 0x1)
|
||||||
|
return CryptoUtils.decryptAES_GCM_NoPad(message, secretKey, iv, null);
|
||||||
return CryptoUtils.decryptAES_CBC_Pad(message, secretKey, iv);
|
return CryptoUtils.decryptAES_CBC_Pad(message, secretKey, iv);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new CryptoException(e);
|
throw new CryptoException(e);
|
||||||
|
@ -57,6 +57,7 @@ public class HuaweiPacket {
|
|||||||
|
|
||||||
protected byte interval;
|
protected byte interval;
|
||||||
protected byte authAlgo;
|
protected byte authAlgo;
|
||||||
|
protected byte encryptMethod;
|
||||||
|
|
||||||
public void setAuthVersion(byte authVersion) {
|
public void setAuthVersion(byte authVersion) {
|
||||||
this.authVersion = authVersion;
|
this.authVersion = authVersion;
|
||||||
@ -144,6 +145,14 @@ public class HuaweiPacket {
|
|||||||
public byte getAuthAlgo () {
|
public byte getAuthAlgo () {
|
||||||
return this.authAlgo;
|
return this.authAlgo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setEncryptMethod(byte encryptMethod) {
|
||||||
|
this.encryptMethod = encryptMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getEncryptMethod () {
|
||||||
|
return this.encryptMethod;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static abstract class ParseException extends Exception {
|
public static abstract class ParseException extends Exception {
|
||||||
|
@ -78,6 +78,7 @@ public class DeviceConfig {
|
|||||||
public byte authAlgo = 0x00;
|
public byte authAlgo = 0x00;
|
||||||
public byte bondState = 0x00;
|
public byte bondState = 0x00;
|
||||||
public short interval = 0x0;
|
public short interval = 0x0;
|
||||||
|
public byte encryptMethod = 0x00;
|
||||||
|
|
||||||
public Response(ParamsProvider paramsProvider) {
|
public Response(ParamsProvider paramsProvider) {
|
||||||
super(paramsProvider);
|
super(paramsProvider);
|
||||||
@ -111,6 +112,9 @@ public class DeviceConfig {
|
|||||||
|
|
||||||
if (this.tlv.contains(0x09))
|
if (this.tlv.contains(0x09))
|
||||||
this.bondState = this.tlv.getByte(0x09);
|
this.bondState = this.tlv.getByte(0x09);
|
||||||
|
|
||||||
|
if (this.tlv.contains(0x0C))
|
||||||
|
this.encryptMethod = this.tlv.getByte(0x0C);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1400,7 +1404,7 @@ public class DeviceConfig {
|
|||||||
|
|
||||||
HuaweiCrypto huaweiCrypto = new HuaweiCrypto(paramsProvider.getAuthVersion());
|
HuaweiCrypto huaweiCrypto = new HuaweiCrypto(paramsProvider.getAuthVersion());
|
||||||
try {
|
try {
|
||||||
pinCode = huaweiCrypto.decryptPinCode(message, iv);
|
pinCode = huaweiCrypto.decryptPinCode(paramsProvider.getEncryptMethod(), message, iv);
|
||||||
} catch (HuaweiCrypto.CryptoException e) {
|
} catch (HuaweiCrypto.CryptoException e) {
|
||||||
throw new CryptoException("Could not decrypt pinCode", e);
|
throw new CryptoException("Could not decrypt pinCode", e);
|
||||||
}
|
}
|
||||||
@ -1487,7 +1491,7 @@ public class DeviceConfig {
|
|||||||
this.tlv = new HuaweiTLV()
|
this.tlv = new HuaweiTLV()
|
||||||
.put(0x01, authMode);
|
.put(0x01, authMode);
|
||||||
if (authMode == 0x02 || authMode == 0x04)
|
if (authMode == 0x02 || authMode == 0x04)
|
||||||
this.tlv.put(0x02, (byte)0x01);
|
this.tlv.put(0x02, (byte)0x01); //force to not reconnected else 0x02
|
||||||
this.tlv.put(0x05, deviceUUID)
|
this.tlv.put(0x05, deviceUUID)
|
||||||
.put(0x03, (byte)0x01)
|
.put(0x03, (byte)0x01)
|
||||||
.put(0x04, (byte)0x00);
|
.put(0x04, (byte)0x00);
|
||||||
|
@ -331,6 +331,7 @@ public class HuaweiSupportProvider {
|
|||||||
initializeDeviceHiChainMode(linkParamsReq);
|
initializeDeviceHiChainMode(linkParamsReq);
|
||||||
} else if (securityNegoReq.authType == 0x01 || securityNegoReq.authType == 0x02) {
|
} else if (securityNegoReq.authType == 0x01 || securityNegoReq.authType == 0x02) {
|
||||||
LOG.debug("HiChain Lite mode");
|
LOG.debug("HiChain Lite mode");
|
||||||
|
// Keep track the gadget is connected
|
||||||
initializeDeviceHiChainLiteMode(linkParamsReq);
|
initializeDeviceHiChainLiteMode(linkParamsReq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
@ -30,6 +31,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCrypto;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.DeviceConfig;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.DeviceConfig;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||||
|
|
||||||
public class GetAuthRequest extends Request {
|
public class GetAuthRequest extends Request {
|
||||||
@ -73,12 +75,13 @@ public class GetAuthRequest extends Request {
|
|||||||
.put(clientNonce)
|
.put(clientNonce)
|
||||||
.array();
|
.array();
|
||||||
byte[] challenge = huaweiCrypto.digestChallenge(key, doubleNonce);
|
byte[] challenge = huaweiCrypto.digestChallenge(key, doubleNonce);
|
||||||
|
LOG.debug("challenge: " + GB.hexdump(challenge));
|
||||||
if (challenge == null)
|
if (challenge == null)
|
||||||
throw new RequestCreationException("Challenge null");
|
throw new RequestCreationException("Challenge null");
|
||||||
return new DeviceConfig.Auth.Request(paramsProvider, challenge, nonce).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 | InvalidKeySpecException e) {
|
} catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | UnsupportedEncodingException e) {
|
||||||
throw new RequestCreationException("Digest exception", e);
|
throw new RequestCreationException("Digest exception", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,7 +105,7 @@ public class GetAuthRequest extends Request {
|
|||||||
+ StringUtils.bytesToHex(expectedAnswer)
|
+ StringUtils.bytesToHex(expectedAnswer)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException e) {
|
} catch (NoSuchAlgorithmException | InvalidKeyException | InvalidKeySpecException | UnsupportedEncodingException e) {
|
||||||
throw new ResponseParseException("Challenge response digest exception");
|
throw new ResponseParseException("Challenge response digest exception");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,5 +84,6 @@ public class GetLinkParamsRequest extends Request {
|
|||||||
this.bondState = ((LinkParams.Response) receivedPacket).bondState;
|
this.bondState = ((LinkParams.Response) receivedPacket).bondState;
|
||||||
|
|
||||||
paramsProvider.setAuthAlgo(((LinkParams.Response) receivedPacket).authAlgo);
|
paramsProvider.setAuthAlgo(((LinkParams.Response) receivedPacket).authAlgo);
|
||||||
|
paramsProvider.setEncryptMethod(((LinkParams.Response) receivedPacket).encryptMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package nodomain.freeyourgadget.gadgetbridge.util;
|
|||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
@ -133,10 +134,9 @@ public class CryptoUtils {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] pbkdf2Sha256(byte[] key, byte[] iv, int count, int length) throws InvalidKeySpecException, NoSuchAlgorithmException {
|
public static byte[] pbkdf2Sha256(String key, String iv, int count, int length) throws InvalidKeySpecException, NoSuchAlgorithmException, UnsupportedEncodingException {
|
||||||
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
|
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
|
||||||
String keyStr = new String(key, StandardCharsets.UTF_8);
|
PBEKeySpec keySpec = new PBEKeySpec(key.toCharArray(), iv.getBytes("utf-8"), count, length);
|
||||||
PBEKeySpec keySpec = new PBEKeySpec(keyStr.toCharArray(), iv, count, length);
|
|
||||||
return secretKeyFactory.generateSecret(keySpec).getEncoded();
|
return secretKeyFactory.generateSecret(keySpec).getEncoded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user