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
Branches
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
String key = MessageUtils.byteArrayToHexString((byte[]) keyResponse.readObject());
realm.beginTransaction();
info.setHmac(hmac);
info.setKey(key);
realm.commitTransaction();
}
......
......@@ -9,6 +9,7 @@ import java.io.IOException;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
......@@ -36,6 +37,7 @@ import info.nightscout.android.medtronic.message.PumpStatusResponseMessage;
import info.nightscout.android.medtronic.message.PumpTimeRequestMessage;
import info.nightscout.android.medtronic.message.PumpTimeResponseMessage;
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.model.medtronicNg.PumpStatusEvent;
import info.nightscout.android.utils.HexDump;
......@@ -238,7 +240,7 @@ public class MedtronicCnlReader implements ContourNextLinkMessageHandler {
Log.d(TAG, "Finished enterPasshtroughMode");
}
public void openConnection() throws IOException, TimeoutException {
public void openConnection() throws IOException, TimeoutException, NoSuchAlgorithmException {
Log.d(TAG, "Begin openConnection");
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
......@@ -264,6 +266,24 @@ public class MedtronicCnlReader implements ContourNextLinkMessageHandler {
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 {
ArrayList<Byte> radioChannels = new ArrayList<>(Arrays.asList(ArrayUtils.toObject(RADIO_CHANNELS)));
......
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.
*/
public class MedtronicCnlSession {
private static final String HMAC_PADDING = "A4BD6CED9A42602564F413123";
private byte[] HMAC;
private byte[] key;
private String stickSerial;
private long linkMAC;
private long pumpMAC;
......@@ -14,16 +23,31 @@ public class MedtronicCnlSession {
private int bayerSequenceNumber = 1;
private int medtronicSequenceNumber = 1;
public byte[] getHMAC() {
/*public byte[] getHMAC() {
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() {
return key;
}
public byte[] getIV() {
byte[] iv = new byte[key.length];
System.arraycopy(key,0,iv,0,key.length);
System.arraycopy(key, 0, iv, 0, key.length);
iv[0] = radioChannel;
return iv;
}
......@@ -32,7 +56,7 @@ public class MedtronicCnlSession {
return linkMAC;
}
public void setLinkMAC( long linkMAC ) {
public void setLinkMAC(long linkMAC) {
this.linkMAC = linkMAC;
}
......@@ -40,7 +64,7 @@ public class MedtronicCnlSession {
return pumpMAC;
}
public void setPumpMAC( long pumpMAC ) {
public void setPumpMAC(long pumpMAC) {
this.pumpMAC = pumpMAC;
}
......@@ -68,11 +92,39 @@ public class MedtronicCnlSession {
this.radioChannel = radioChannel;
}
public void setHMAC( byte[] hmac ) {
public void setHMAC(byte[] hmac) {
this.HMAC = hmac;
}
public void setKey( byte[] key ) {
public void setKey(byte[] 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{
CommandType(int commandType) {
value = (byte) commandType;
}
public int getValue() {
return value;
}
}
public ContourNextLinkBinaryMessage(CommandType commandType, MedtronicCnlSession pumpSession, byte[] payload) {
......
......@@ -45,7 +45,10 @@ public class MedtronicReceiveMessage extends MedtronicMessage {
// 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( 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)
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;
import android.util.Log;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeoutException;
......@@ -157,6 +158,9 @@ public class MedtronicCnlIntentService extends IntentService {
info = realm.copyToRealm(info);
}
cnlReader.getPumpSession().setStickSerial(info.getSerialNumber());
/*
String hmac = info.getHmac();
String key = info.getKey();
......@@ -173,6 +177,7 @@ public class MedtronicCnlIntentService extends IntentService {
cnlReader.getPumpSession().setHMAC(MessageUtils.hexStringToByteArray(hmac));
cnlReader.getPumpSession().setKey(MessageUtils.hexStringToByteArray(key));
*/
cnlReader.enterControlMode();
......@@ -181,6 +186,17 @@ public class MedtronicCnlIntentService extends IntentService {
cnlReader.openConnection();
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();
Log.i(TAG, "PumpInfo MAC: " + (pumpMAC & 0xffffff));
MainActivity.setActivePumpMac(pumpMAC);
......@@ -250,6 +266,9 @@ public class MedtronicCnlIntentService extends IntentService {
} catch (UnexpectedMessageException e) {
Log.e(TAG, "Unexpected Message", e);
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 {
//TODO : 05.11.2016 has the close to be here?
cnlReader.closeConnection();
......@@ -304,7 +323,7 @@ public class MedtronicCnlIntentService extends IntentService {
final Intent receiverIntent = new Intent(this, XDripPlusUploadReceiver.class);
final long timestamp = System.currentTimeMillis() + 500L;
final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, (int) timestamp, receiverIntent, PendingIntent.FLAG_ONE_SHOT);
Log.d(TAG,"Scheduling xDrip+ send");
Log.d(TAG, "Scheduling xDrip+ send");
wakeUpIntent(getApplicationContext(), timestamp, pendingIntent);
}
}
......@@ -312,7 +331,7 @@ public class MedtronicCnlIntentService extends IntentService {
private void uploadToNightscout() {
Intent receiverIntent = new Intent(this, NightscoutUploadReceiver.class);
final long timestamp = System.currentTimeMillis() + 1000L;
final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, (int)timestamp, receiverIntent, PendingIntent.FLAG_ONE_SHOT);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, (int) timestamp, receiverIntent, PendingIntent.FLAG_ONE_SHOT);
wakeUpIntent(getApplicationContext(), timestamp, pendingIntent);
}
......
......@@ -9,7 +9,6 @@ import io.realm.annotations.PrimaryKey;
public class ContourNextLinkInfo extends RealmObject {
@PrimaryKey
private String serialNumber;
private String hmac;
private String key;
public String getSerialNumber() {
......@@ -20,14 +19,6 @@ public class ContourNextLinkInfo extends RealmObject {
this.serialNumber = serialNumber;
}
public String getHmac() {
return hmac;
}
public void setHmac(String hmac) {
this.hmac = hmac;
}
public String getKey() {
return key;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment