1

I need to read an encrypted message sent from a device with ATMEL chip.

The Communication flow is attached here:

Communication flow

I did everything about socket communication and ECDSA signature verifying.

Now I am stuck at the decrypt phase.

The data needed for an example decryption is the following:

// 0 - private key (prv-h, android host) : "308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104206cb80a311272dae8a6bf01273c865a7d2890c16436330b88cb53d2bc55133f23a00a06082a8648ce3d030107a144034200046342f6b12beab7dd829bb95cee5073c8968e1cb406c185ab6dfd8889df0aec1f7ed1a31af57a0df00454cd683d83ee490e6747adbb6d6d68ab345149e7de1366"
// 1 / public ephemereal key (device pub-x): "04F0442494445A67606873A943F228A11FEE28B56502B3753E1FD4B5A369BA62B9DF0965C27E069E4997893CDBCC06B72A39907632FF6E4740597970F3DBEC9A17"
// 2 / encrypted message: "5A92B516C7F6C29168879D913F4D6210EC689419C16B67FB17365CB8C2363D80" "C263D7389158EB0ADF4470FC689CA6726F87EC82C3DCEAE49005C90230034DF7" (2 blocks of 64 bytes. I still don't know if i can collate them or decrypt one by one)
// 3 / iv (generated by device and sent) : "28395B5C43A82E3951B153A33B10B01C"
// 4 / randNum1 (generated by android and previously sent to device): "9f7ed0f97069b01b097f1e6b7e28465678a0b7cd45cfb354de0632b308879f94"

I try to decrypt using the flow found here:

Android Pay API example

but i found some diferences, overall being it verify-then-decrypy, while i need a decrypt-then-mac solution.

Also, that solution relies on a "tag" that I think I don't have.

And also, that solution doesn't use a randNum previously sent by the host.

At the moment, I can do this:

public static String DeCrypt(String privateKey_s, String ephemeralPublicKey_s, String message_s, String tag_s, String iv_s, String randNum1_s) throws Exception {
    // premasterkey = ecdh(private, public)
    PrivateKey privateKey = FromHexStringToPrivateKey(privateKey_s);
    PublicKey ephemeralPublicKey = FromCompactStringToPublicKey(ephemeralPublicKey_s);
    KeyAgreement ka = KeyAgreement.getInstance("ECDH");
    ka.init(privateKey);
    ka.doPhase(ephemeralPublicKey, true);
    byte[] preMasterKey = ka.generateSecret();

Here, I get a 16 bytes (32 hex chars) preMasterKey. I think it is correct. But from this point, I don't know how to do well. I see that the reference code mixes the public key with the shared secret (preMasterKey) to get the session key (encryption key), but my flow requires that the session key is derived from randNum1 and preMasterKey

    byte[] randNum1 = hexStringToByteArray(randNum1_s);
    byte[] message = hexStringToByteArray(message_s);
    byte[] iv = hexStringToByteArray(iv_s);

    // Deriving encryption and mac keys.
    HKDFBytesGenerator hkdfBytesGenerator = new HKDFBytesGenerator(new SHA256Digest());
    byte[] khdfInput = ByteUtils.concatenate(randNum1, preMasterKey);
    hkdfBytesGenerator.init(new HKDFParameters(khdfInput, null, "Android".getBytes(Charset.forName("UTF-8"))));
    byte[] encryptionKey = new byte[16];
    hkdfBytesGenerator.generateBytes(encryptionKey, 0, 16);
    byte[] macKey = new byte[16];
    hkdfBytesGenerator.generateBytes(macKey, 0, 16);

    // Verifying Message Authentication Code (aka mac/tag)
    Mac macGenerator = Mac.getInstance("HmacSHA256", "BC");
    macGenerator.init(new SecretKeySpec(macKey, "HmacSHA256"));
    byte[] expectedTag = macGenerator.doFinal(messaggio);
    //    if (!isArrayEqual(tag, expectedTag)) {
    //        throw new RuntimeException("Bad Message Authentication Code!");
    //      }

    // Decrypting the message.
    Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
    cipher.init(
        Cipher.DECRYPT_MODE,
        new SecretKeySpec(encryptionKey, "AES"),
    new IvParameterSpec(iv));
    return new String(cipher.doFinal(messaggio));
}

Addendum

Maybe my private key is badly formatted.

I generated the pair through this piece of code:

public String GenKeysHex() throws Exception {
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
    kpg.initialize(256);
    KeyPair keyPair = kpg.generateKeyPair();
    PrivateKey prv = keyPair.getPrivate();
    PublicKey pub = keyPair.getPublic();

    byte[] prvBytes = prv.getEncoded();
    byte[] pubBytes = pub.getEncoded();

    String result1 = new BigInteger(1, prvBytes).toString(16);
    String result2 = new BigInteger(1, pubBytes).toString(16);

    String result3 = FromLongToCompactPublic(result2);

    return result3 + "," + result1 + "," + result2 ;
}

public static PrivateKey FromHexToPrivateKey(String Hex) throws Exception {
    byte[] hardcodedPrivate = hexStringToByteArray(Hex);
    PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(hardcodedPrivate);
    KeyFactory factory = KeyFactory.getInstance("EC");
    PrivateKey privateKey = factory.generatePrivate(privateSpec);
    return privateKey;
}

public static String FromPrivateKeyToHex(PrivateKey key) throws Exception {
    byte[] prvBytes = key.getEncoded();
    String result1 = new BigInteger(1, prvBytes).toString(16);
    return result1;
}

This is because i need to create a library and I need to exchange import/export data in String format, so I checked that the text/Hex format of the private key would be consistent through the other two routines.

I wonder how to to get the private key in a more compact form.


Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
  • The MAC in your scheme isn't used for message authentication at all, it is just used as a KDF (key derivation function). It derives the encryption key and a value (`DevMacCalc`) that is used for *entity authentication of the device*. Although you may borrow some things such as algorithm instantiation and initialization from the code you linked to, it should not act as a starting point for your decryption routine. – Maarten Bodewes Feb 13 '17 at 13:09
  • Well, thanks a lot. I am totally stuck. The chip is ATECC508A and I cannot find anything that can address me towards how to get the sessionKey from MAC(randNum1, preMasterKey). I am totally unaware about cryptography and Java also. I am just an "algorithm integrator". I tried to search around, but I couldn't find anything that combines ECDH, MAC and AES communication between two heterogeneous systems. Can you address me to somewhere please? – Pierpaolo Palazzo Feb 13 '17 at 14:02
  • The (leftmost) bytes of the MAC output are just directly used as key or as value to compare for a KDF construction. I am not very knowledgeable with regards to persons performing these kind of services. I can do it almost without thinking but I don't have the required company / time etc. – Maarten Bodewes Feb 13 '17 at 14:16
  • Aside from the other issues, your private key here looks _very_ long. – matt Feb 13 '17 at 22:31
  • ...which is because (after a bit of investigation) it’s actually a DER encoded public key, _not_ the private key. So even if we could work out how the key derivation should work there isn’t enough info here to decrypt anything—we have two public keys, not a private key and a public key. – matt Feb 13 '17 at 23:15
  • Hello, thanks a lot for addressing me. I added the code used to generate and store the private key. Is there a better way to store in ASCII/UTF8 format the prv key? – Pierpaolo Palazzo Feb 14 '17 at 00:01

0 Answers0