diff --git a/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java b/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java
index 64c30b3aea050802499e70eac5b49b00e373fbea..f283f844fbee0a6529dfaa5ab52e549bec048f92 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java
@@ -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();
                     }
diff --git a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java
index f4aeb0c90953398ab78394ea7f1600430657958b..6dd908f0dd3f57b8d8c585d51690eaee4b82df5b 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java
@@ -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)));
 
diff --git a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java
index 0f22dd79dc7950f50849f69d7397288e900a7181..215e7f3e6174163da35db8824c928d87f5d454bb 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java
@@ -1,12 +1,21 @@
 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;
+    }
 }
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryMessage.java
index c5b8107a3c4c7aed1fd091f0312e8a51e76b3297..95e94baa56ef73718e3db0d2d13e272f8b48a058 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryMessage.java
@@ -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) {
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicReceiveMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicReceiveMessage.java
index 28dd3a5e76d16ea819f742f6487d0ff563c7fef9..c2f4a7d58cf10d70925e3d2ab15e3358a4ff3a3f 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicReceiveMessage.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicReceiveMessage.java
@@ -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];
 
diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/RequestLinkKeyResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/RequestLinkKeyResponseMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..423e40fb8ab61296fc9c26995837a56932715a7e
--- /dev/null
+++ b/app/src/main/java/info/nightscout/android/medtronic/message/RequestLinkKeyResponseMessage.java
@@ -0,0 +1,21 @@
+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
diff --git a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java
index 5a403aa65172fda96de03c2d04022b18acec924d..814f29de870282cf6b54da5c6619dbbadc4f6864 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java
@@ -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);
     }
 
diff --git a/app/src/main/java/info/nightscout/android/model/medtronicNg/ContourNextLinkInfo.java b/app/src/main/java/info/nightscout/android/model/medtronicNg/ContourNextLinkInfo.java
index 404d801c8250aaa33c13ca53e58b0d9f0e852a05..9b054671a3580a5c5e142405e89d8ea52147e100 100644
--- a/app/src/main/java/info/nightscout/android/model/medtronicNg/ContourNextLinkInfo.java
+++ b/app/src/main/java/info/nightscout/android/model/medtronicNg/ContourNextLinkInfo.java
@@ -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;
     }