Skip to content
Snippets Groups Projects
Commit a323eb70 authored by Lennart Goedhart's avatar Lennart Goedhart
Browse files

Remove dependence on CareLink to get CNL HMAC and encryption key.

parent 3156be4d
No related branches found
No related tags found
No related merge requests found
Showing with 129 additions and 20 deletions
...@@ -340,7 +340,6 @@ public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCa ...@@ -340,7 +340,6 @@ public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCa
String key = MessageUtils.byteArrayToHexString((byte[]) keyResponse.readObject()); String key = MessageUtils.byteArrayToHexString((byte[]) keyResponse.readObject());
realm.beginTransaction(); realm.beginTransaction();
info.setHmac(hmac);
info.setKey(key); info.setKey(key);
realm.commitTransaction(); realm.commitTransaction();
} }
......
...@@ -9,6 +9,7 @@ import java.io.IOException; ...@@ -9,6 +9,7 @@ import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
...@@ -36,6 +37,7 @@ import info.nightscout.android.medtronic.message.PumpStatusResponseMessage; ...@@ -36,6 +37,7 @@ import info.nightscout.android.medtronic.message.PumpStatusResponseMessage;
import info.nightscout.android.medtronic.message.PumpTimeRequestMessage; import info.nightscout.android.medtronic.message.PumpTimeRequestMessage;
import info.nightscout.android.medtronic.message.PumpTimeResponseMessage; import info.nightscout.android.medtronic.message.PumpTimeResponseMessage;
import info.nightscout.android.medtronic.message.ReadInfoResponseMessage; import info.nightscout.android.medtronic.message.ReadInfoResponseMessage;
import info.nightscout.android.medtronic.message.RequestLinkKeyResponseMessage;
import info.nightscout.android.medtronic.message.UnexpectedMessageException; import info.nightscout.android.medtronic.message.UnexpectedMessageException;
import info.nightscout.android.model.medtronicNg.PumpStatusEvent; import info.nightscout.android.model.medtronicNg.PumpStatusEvent;
import info.nightscout.android.utils.HexDump; import info.nightscout.android.utils.HexDump;
...@@ -238,7 +240,7 @@ public class MedtronicCnlReader implements ContourNextLinkMessageHandler { ...@@ -238,7 +240,7 @@ public class MedtronicCnlReader implements ContourNextLinkMessageHandler {
Log.d(TAG, "Finished enterPasshtroughMode"); Log.d(TAG, "Finished enterPasshtroughMode");
} }
public void openConnection() throws IOException, TimeoutException { public void openConnection() throws IOException, TimeoutException, NoSuchAlgorithmException {
Log.d(TAG, "Begin openConnection"); Log.d(TAG, "Begin openConnection");
new ContourNextLinkBinaryMessage(ContourNextLinkBinaryMessage.CommandType.OPEN_CONNECTION, mPumpSession, mPumpSession.getHMAC()).send(this); new ContourNextLinkBinaryMessage(ContourNextLinkBinaryMessage.CommandType.OPEN_CONNECTION, mPumpSession, mPumpSession.getHMAC()).send(this);
// FIXME - We need to care what the response message is - wrong MAC and all that // FIXME - We need to care what the response message is - wrong MAC and all that
...@@ -264,6 +266,24 @@ public class MedtronicCnlReader implements ContourNextLinkMessageHandler { ...@@ -264,6 +266,24 @@ public class MedtronicCnlReader implements ContourNextLinkMessageHandler {
Log.d(TAG, String.format("Finished requestReadInfo. linkMAC = '%d', pumpMAC = '%d", linkMAC, pumpMAC)); Log.d(TAG, String.format("Finished requestReadInfo. linkMAC = '%d', pumpMAC = '%d", linkMAC, pumpMAC));
} }
public void requestLinkKey() throws IOException, TimeoutException, EncryptionException, ChecksumException {
Log.d(TAG, "Begin requestLinkKey");
new ContourNextLinkBinaryMessage(ContourNextLinkBinaryMessage.CommandType.REQUEST_LINK_KEY, mPumpSession, null).send(this);
ContourNextLinkMessage response = RequestLinkKeyResponseMessage.fromBytes(mPumpSession, readMessage());
// FIXME - this needs to go into RequestLinkKeyResponseMessage
ByteBuffer infoBuffer = ByteBuffer.allocate(55);
infoBuffer.order(ByteOrder.BIG_ENDIAN);
infoBuffer.put(response.encode(), 0x21, 55);
byte[] packedLinkKey = infoBuffer.array();
this.getPumpSession().setPackedLinkKey(packedLinkKey);
Log.d(TAG, String.format("Finished requestLinkKey. linkKey = '%s'", this.getPumpSession().getKey()));
}
public byte negotiateChannel(byte lastRadioChannel) throws IOException, ChecksumException, TimeoutException { public byte negotiateChannel(byte lastRadioChannel) throws IOException, ChecksumException, TimeoutException {
ArrayList<Byte> radioChannels = new ArrayList<>(Arrays.asList(ArrayUtils.toObject(RADIO_CHANNELS))); ArrayList<Byte> radioChannels = new ArrayList<>(Arrays.asList(ArrayUtils.toObject(RADIO_CHANNELS)));
......
package info.nightscout.android.medtronic; package info.nightscout.android.medtronic;
import org.apache.commons.lang3.ArrayUtils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/** /**
* Created by lgoedhart on 26/03/2016. * Created by lgoedhart on 26/03/2016.
*/ */
public class MedtronicCnlSession { public class MedtronicCnlSession {
private static final String HMAC_PADDING = "A4BD6CED9A42602564F413123";
private byte[] HMAC; private byte[] HMAC;
private byte[] key; private byte[] key;
private String stickSerial;
private long linkMAC; private long linkMAC;
private long pumpMAC; private long pumpMAC;
...@@ -14,13 +23,28 @@ public class MedtronicCnlSession { ...@@ -14,13 +23,28 @@ public class MedtronicCnlSession {
private int bayerSequenceNumber = 1; private int bayerSequenceNumber = 1;
private int medtronicSequenceNumber = 1; private int medtronicSequenceNumber = 1;
public byte[] getHMAC() { /*public byte[] getHMAC() {
return HMAC; return HMAC;
}*/
public byte[] getHMAC() throws NoSuchAlgorithmException {
String shortSerial = this.stickSerial.replaceAll("\\d+-", "");
byte[] message = (shortSerial + HMAC_PADDING).getBytes();
byte[] numArray;
MessageDigest instance = MessageDigest.getInstance("SHA-256");
instance.update(message);
numArray = instance.digest();
ArrayUtils.reverse(numArray);
return numArray;
} }
public byte[] getKey() { public byte[] getKey() {
return key; return key;
} }
public byte[] getIV() { public byte[] getIV() {
byte[] iv = new byte[key.length]; byte[] iv = new byte[key.length];
System.arraycopy(key, 0, iv, 0, key.length); System.arraycopy(key, 0, iv, 0, key.length);
...@@ -75,4 +99,32 @@ public class MedtronicCnlSession { ...@@ -75,4 +99,32 @@ public class MedtronicCnlSession {
public void setKey(byte[] key) { public void setKey(byte[] key) {
this.key = key; this.key = key;
} }
public void setPackedLinkKey(byte[] packedLinkKey) {
this.key = new byte[16];
int pos = this.stickSerial.charAt(this.stickSerial.length() - 1) & 7;
for (int i = 0; i < this.key.length; i++) {
if ((packedLinkKey[pos + 1] & 1) == 1) {
this.key[i] = (byte) ~packedLinkKey[pos];
} else {
this.key[i] = packedLinkKey[pos];
}
if (((packedLinkKey[pos + 1] >> 1) & 1) == 0) {
pos += 3;
} else {
pos += 2;
}
}
}
public String getStickSerial() {
return stickSerial;
}
public void setStickSerial(String stickSerial) {
this.stickSerial = stickSerial;
}
} }
...@@ -34,6 +34,10 @@ public class ContourNextLinkBinaryMessage extends ContourNextLinkMessage{ ...@@ -34,6 +34,10 @@ public class ContourNextLinkBinaryMessage extends ContourNextLinkMessage{
CommandType(int commandType) { CommandType(int commandType) {
value = (byte) commandType; value = (byte) commandType;
} }
public int getValue() {
return value;
}
} }
public ContourNextLinkBinaryMessage(CommandType commandType, MedtronicCnlSession pumpSession, byte[] payload) { public ContourNextLinkBinaryMessage(CommandType commandType, MedtronicCnlSession pumpSession, byte[] payload) {
......
...@@ -45,7 +45,10 @@ public class MedtronicReceiveMessage extends MedtronicMessage { ...@@ -45,7 +45,10 @@ public class MedtronicReceiveMessage extends MedtronicMessage {
// TODO - Validate the message, inner CCITT, serial numbers, etc // TODO - Validate the message, inner CCITT, serial numbers, etc
// If there's not 57 bytes, then we got back a bad message. Not sure how to process these yet. // If there's not 57 bytes, then we got back a bad message. Not sure how to process these yet.
if( bytes.length >= 57 ) { // Also, READ_INFO and REQUEST_LINK_KEY are not encrypted
if (bytes.length >= 57 &&
(bytes[18] != CommandType.READ_INFO.getValue()) &&
(bytes[18] != CommandType.REQUEST_LINK_KEY_RESPONSE.getValue())) {
// Replace the encrypted bytes by their decrypted equivalent (same block size) // Replace the encrypted bytes by their decrypted equivalent (same block size)
byte encryptedPayloadSize = bytes[56]; byte encryptedPayloadSize = bytes[56];
......
package info.nightscout.android.medtronic.message;
import info.nightscout.android.medtronic.MedtronicCnlSession;
/**
* Created by lgoedhart on 10/05/2016.
*/
public class RequestLinkKeyResponseMessage extends MedtronicReceiveMessage {
protected RequestLinkKeyResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCnlSession pumpSession, byte[] payload) {
super(commandType, commandAction, pumpSession, payload);
}
public static ContourNextLinkMessage fromBytes(MedtronicCnlSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
// TODO - turn this into a factory
ContourNextLinkMessage message = MedtronicReceiveMessage.fromBytes(pumpSession, bytes);
// TODO - Validate the MessageType
return message;
}
}
\ No newline at end of file
...@@ -16,6 +16,7 @@ import android.support.v4.content.LocalBroadcastManager; ...@@ -16,6 +16,7 @@ import android.support.v4.content.LocalBroadcastManager;
import android.util.Log; import android.util.Log;
import java.io.IOException; import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
...@@ -157,6 +158,9 @@ public class MedtronicCnlIntentService extends IntentService { ...@@ -157,6 +158,9 @@ public class MedtronicCnlIntentService extends IntentService {
info = realm.copyToRealm(info); info = realm.copyToRealm(info);
} }
cnlReader.getPumpSession().setStickSerial(info.getSerialNumber());
/*
String hmac = info.getHmac(); String hmac = info.getHmac();
String key = info.getKey(); String key = info.getKey();
...@@ -173,6 +177,7 @@ public class MedtronicCnlIntentService extends IntentService { ...@@ -173,6 +177,7 @@ public class MedtronicCnlIntentService extends IntentService {
cnlReader.getPumpSession().setHMAC(MessageUtils.hexStringToByteArray(hmac)); cnlReader.getPumpSession().setHMAC(MessageUtils.hexStringToByteArray(hmac));
cnlReader.getPumpSession().setKey(MessageUtils.hexStringToByteArray(key)); cnlReader.getPumpSession().setKey(MessageUtils.hexStringToByteArray(key));
*/
cnlReader.enterControlMode(); cnlReader.enterControlMode();
...@@ -181,6 +186,17 @@ public class MedtronicCnlIntentService extends IntentService { ...@@ -181,6 +186,17 @@ public class MedtronicCnlIntentService extends IntentService {
cnlReader.openConnection(); cnlReader.openConnection();
cnlReader.requestReadInfo(); cnlReader.requestReadInfo();
String key = info.getKey();
if (key == null) {
cnlReader.requestLinkKey();
info.setKey(MessageUtils.byteArrayToHexString(cnlReader.getPumpSession().getKey()));
key = info.getKey();
}
cnlReader.getPumpSession().setKey(MessageUtils.hexStringToByteArray(key));
long pumpMAC = cnlReader.getPumpSession().getPumpMAC(); long pumpMAC = cnlReader.getPumpSession().getPumpMAC();
Log.i(TAG, "PumpInfo MAC: " + (pumpMAC & 0xffffff)); Log.i(TAG, "PumpInfo MAC: " + (pumpMAC & 0xffffff));
MainActivity.setActivePumpMac(pumpMAC); MainActivity.setActivePumpMac(pumpMAC);
...@@ -250,6 +266,9 @@ public class MedtronicCnlIntentService extends IntentService { ...@@ -250,6 +266,9 @@ public class MedtronicCnlIntentService extends IntentService {
} catch (UnexpectedMessageException e) { } catch (UnexpectedMessageException e) {
Log.e(TAG, "Unexpected Message", e); Log.e(TAG, "Unexpected Message", e);
sendStatus("Communication Error: " + e.getMessage()); sendStatus("Communication Error: " + e.getMessage());
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "Could not determine CNL HMAC", e);
sendStatus("Error connecting to Contour Next Link: Hashing error.");
} finally { } finally {
//TODO : 05.11.2016 has the close to be here? //TODO : 05.11.2016 has the close to be here?
cnlReader.closeConnection(); cnlReader.closeConnection();
......
...@@ -9,7 +9,6 @@ import io.realm.annotations.PrimaryKey; ...@@ -9,7 +9,6 @@ import io.realm.annotations.PrimaryKey;
public class ContourNextLinkInfo extends RealmObject { public class ContourNextLinkInfo extends RealmObject {
@PrimaryKey @PrimaryKey
private String serialNumber; private String serialNumber;
private String hmac;
private String key; private String key;
public String getSerialNumber() { public String getSerialNumber() {
...@@ -20,14 +19,6 @@ public class ContourNextLinkInfo extends RealmObject { ...@@ -20,14 +19,6 @@ public class ContourNextLinkInfo extends RealmObject {
this.serialNumber = serialNumber; this.serialNumber = serialNumber;
} }
public String getHmac() {
return hmac;
}
public void setHmac(String hmac) {
this.hmac = hmac;
}
public String getKey() { public String getKey() {
return key; return key;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment