AES-шифрование javacardx не совпадает с AES-дешифрованием javax - PullRequest
0 голосов
/ 27 мая 2018

Я разрабатываю смарт-карту, которая связывается через промежуточное ПО с сервером.Сервер должен аутентифицировать себя на смарт-карте.Частью этого процесса аутентификации является вызов, который зашифрован с помощью ключа сеанса.Сервер должен расшифровать вызов с помощью сеансового ключа.Это происходит со следующими параметрами шифра:

Алгоритм: AES Mode: CBC Padding: noPadding

Код для шифрования на карте:

public class Card extends Applet {

private final static byte[] PUBLIC_KEY_EXPONENT_CA = new byte[] {(byte) 0x1, 0x00, 0x01};
private final static byte[] PUBLIC_KEY_MODULUS_CA = new byte[] { (byte) 0xC0, 0x16, 0x35, 0x2C, 0x2F, 0x0E, 0x6C, 0x6B, (byte) 0x96, (byte) 0x9F, 0x53, 0x0B, 0x00, (byte) 0xE9, 0x05, 0x71, (byte) 0xCB, 0x39, (byte) 0xD0, 0x23, (byte) 0xF0, (byte) 0x80, 0x45, 0x75, 0x00, (byte) 0xCD, (byte) 0x80, (byte) 0xC7, 0x4B, 0x3A, 0x1B, 0x61, (byte) 0x86, (byte) 0xF4, 0x44, (byte) 0xCD, 0x21, 0x63, (byte) 0xCB, 0x44, 0x63, (byte) 0x9D, (byte) 0x97, 0x4F, 0x40, (byte) 0xA4, 0x1E, 0x01, 0x16, 0x39, 0x1D, (byte) 0xE5, 0x67, (byte) 0xBE, 0x01, (byte) 0xC8, (byte) 0x82, 0x52, 0x0B, 0x13, 0x71, (byte) 0xF5, 0x38, 0x21 };
private final RSAPublicKey publicKeyCA;

private final static byte[] PUBLIC_KEY_EXPONENT_SP = new byte[3];
private final static byte[] PUBLIC_KEY_MODULUS_SP = new byte[64];
private final RSAPublicKey publicKeySP;

private final static byte[] KEY_SESSION = new byte[32];
private final static byte[] CHALLENGE_SESSION = new byte[32];

private static final short LENGTH_SIGNATURE = 64;
private static final short LENGTH_TIME = 8;

private final byte[] time = new byte[LENGTH_TIME];
private final byte[] lastValidationTime = new byte[LENGTH_TIME];
private final byte[] differenceTime = new byte[LENGTH_TIME];
private final byte[] signatureBytes = new byte[LENGTH_SIGNATURE];
private final byte[] hash = new byte[20];
private final byte[] storage = new byte[331];

private final RandomData random;
private final Signature signature;
private final MessageDigest digest;
private final Cipher cipherRSA;
private final Cipher cipherAES;

private Card() {
    publicKeySP = (RSAPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, KeyBuilder.LENGTH_RSA_512, false);
    signature = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false);
    digest = MessageDigest.getInstance(MessageDigest.ALG_SHA, false);
    cipherRSA = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
    cipherAES = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);

    random = RandomData.getInstance(RandomData.ALG_PSEUDO_RANDOM) ;
}

public void process(APDU apdu) throws ISOException {

     byte[] buffer = apdu.getBuffer();
     ...
     byte instruction = buffer[ISO7816.OFFSET_INS];
     switch(instruction){
     ...
     case INS_AUTHENTICATE_SP:
        authenticateSP(apdu);
        break;
     default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
    }
}

private void authenticateSP(APDU apdu) {

    loadSPCertificate();

    if (!publicKeySP.isInitialized()) {
        ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
    }

    verifySPCertificate();

    clear(KEY_SESSION);
    clear(CHALLENGE_SESSION);

    AESKey sessionKeySP = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_128, true);
    random.generateData(KEY_SESSION, (short) 0, (short) KEY_SESSION.length);
    sessionKeySP.setKey(KEY_SESSION, (short) 0);
    byte[] sessionKeySPBytesEncrypted = new byte[64];
    cipherRSA.init(publicKeySP, Cipher.MODE_ENCRYPT);
    cipherRSA.doFinal(KEY_SESSION, (short) 0, (short) KEY_SESSION.length, sessionKeySPBytesEncrypted, (short) 0);

    random.generateData(CHALLENGE_SESSION, (short) 0, (short) 32);

    byte[] messageBytes = new byte[128];
    byte[] messageBytesEncrypted = new byte[128];
    Util.arrayCopy(CHALLENGE_SESSION, (short) 0, messageBytes, (short) 0, (short) 32);
    Util.arrayCopy(storage, (short) 0, messageBytes, (short) 32, (short) 64);
    Util.arrayFillNonAtomic(messageBytes, (short) 96, (short) 32, (byte) -1);
    cipherAES.init(sessionKeySP, Cipher.MODE_ENCRYPT, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, (short) 0, (short) 16);
    cipherAES.doFinal(messageBytes, (short) 0, (short) messageBytes.length, messageBytesEncrypted, (short) 0);

    apdu.setOutgoing();
    apdu.setOutgoingLength((short) (sessionKeySPBytesEncrypted.length + messageBytesEncrypted.length));
    apdu.sendBytesLong(sessionKeySPBytesEncrypted, (short) 0, (short) sessionKeySPBytesEncrypted.length);
    apdu.sendBytesLong(messageBytesEncrypted, (short) 0, (short) messageBytesEncrypted.length);
}

private void verifySPCertificate() {
    signature.init(publicKeyCA, Signature.MODE_VERIFY);

    // The signature is used on the hash of the certificate without the signature bytes
    Util.arrayCopy(storage, (short) 267, signatureBytes, (short) 0, (short) LENGTH_SIGNATURE);

    digest.doFinal(storage, (short) 0, (short) 267, hash, (short) 0);

    if (!signature.verify(hash, (short) 0, (short) hash.length, signatureBytes, (short) 0, (short) signatureBytes.length)) {
        ISOException.throwIt(SW_VERIFY_CERTIFICATE_ERROR);
    }

    Util.arrayCopy(storage, (short) 259, time, (short) 0, (short) time.length);
    byte result = BigIntNumber.compare(time, (byte) 259, lastValidationTime, (byte) 0, (byte) LENGTH_TIME);
    if (result < 0) {
        ISOException.throwIt(SW_VERIFY_CERTIFICATE_ERROR);
    }
}

private void loadSPCertificate() {
    Util.arrayCopy(storage, (short) 128, PUBLIC_KEY_EXPONENT_SP, (short) 0, (short) PUBLIC_KEY_EXPONENT_SP.length);
    Util.arrayCopy(storage, (short) 131, PUBLIC_KEY_MODULUS_SP, (short) 0, (short) PUBLIC_KEY_MODULUS_SP.length);
    publicKeySP.setExponent(PUBLIC_KEY_EXPONENT_SP, (short) 0, (short) PUBLIC_KEY_EXPONENT_SP.length);
    publicKeySP.setModulus(PUBLIC_KEY_MODULUS_SP, (short) 0, (short) PUBLIC_KEY_MODULUS_SP.length);
}
}
sessionKeySP: [89, 93, -96, 94, 97, -115, -91, -90, 100, -17, 106, -109, 18, 114, -11, 3, -53, 116, 64, 100, -96, 38, 57, -21, 52, -111, 32, -97, 58, 39, 25, -128]
messageBytes: [32, -52, -49, -20, -85, 41, 125, 116, 45, -53, 53, 20, -53, -84, -128, -67, -114, -68, 66, -96, 67, 78, 61, 115, 112, 84, 97, 120, 79, 110, 87, 101, 98, 44, 32, 68, 67, 61, 101, 71, 111, 118, 101, 114, 110, 109, 101, 110, 116, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
messageBytesEncrypted: [-15, -114, 51, 112, 32, -108, 72, 108, 4, -77, -126, 78, 89, -34, 5, 53, 51, -84, 99, 28, -16, -3, 50, 50, -31, 108, -98, -18, -113, -126, 18, 18, 72, 7, 49, -76, -7, 111, -33, 47, 18, -94, 82, -49, -75, 60, -113, -49, 80, 101, -71, -43, 29, 52, -33, 15, -71, 89, 7, 6, -15, 30, -69, 103, -14, 91, -116, -94, -99, -120, -110, 42, -76, 10, -17, -58, -77, 80, 57, 43, -128, -72, 104, -69, -9, -103, -123, -125, -98, 25, -116, 96, 13, -38, -78, 87, -18, 103, 0, 15, 0, -63, -19, 86, 31, -21, 41, -127, -127, 58, -104, 89, 41, 18, -70, -86, 98, -33, 58, 80, -12, -102, 7, -106, -14, -18, -69, 34]

Код для расшифровкина сервере:

private byte[] verifyAuthenticationServiceProvider(byte[] encryptedData) throws Exception {

    byte[] sessionKeyBytesEncrypted = new byte[64];
    System.arraycopy(encryptedData, 0, sessionKeyBytesEncrypted, 0, 64);
    byte[] messageBytesEncrypted = new byte[128];
    System.arraycopy(encryptedData, 64, messageBytesEncrypted, 0, 128);

    Cipher cipherRSA = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipherRSA.init(Cipher.DECRYPT_MODE, privateKey);
    byte[] sessionKeyBytes = cipherRSA.doFinal(sessionKeyBytesEncrypted);
    SecretKey sessionKey = new SecretKeySpec(sessionKeyBytes, 0, sessionKeyBytes.length, "AES");

    Cipher cipherAES = Cipher.getInstance("AES/CBC/NoPadding");
    IvParameterSpec ivspec = new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 });
    cipherAES.init(Cipher.DECRYPT_MODE, sessionKey, ivspec);
    byte[] messageBytes = cipherAES.doFinal(messageBytesEncrypted);

    byte[] challengeBytes = new byte[32];
    byte[] subjectBytes = new byte[64];
    System.arraycopy(messageBytes, 0, challengeBytes, 0, 32);
    System.arraycopy(messageBytes, 32, subjectBytes, 0, 64);
    ...
}

sessionKey: [89, 93, -96, 94, 97, -115, -91, -90, 100, -17, 106, -109, 18, 114, -11, 3, -53, 116, 64, 100, -96, 38, 57, -21, 52, -111, 32, -97, 58, 39, 25, -128]
messageBytesEncrypted: [-15, -114, 51, 112, 32, -108, 72, 108, 4, -77, -126, 78, 89, -34, 5, 53, 51, -84, 99, 28, -16, -3, 50, 50, -31, 108, -98, -18, -113, -126, 18, 18, 72, 7, 49, -76, -7, 111, -33, 47, 18, -94, 82, -49, -75, 60, -113, -49, 80, 101, -71, -43, 29, 52, -33, 15, -71, 89, 7, 6, -15, 30, -69, 103, -14, 91, -116, -94, -99, -120, -110, 42, -76, 10, -17, -58, -77, 80, 57, 43, -128, -72, 104, -69, -9, -103, -123, -125, -98, 25, -116, 96, 13, -38, -78, 87, -18, 103, 0, 15, 0, -63, -19, 86, 31, -21, 41, -127, -127, 58, -104, 89, 41, 18, -70, -86, 98, -33, 58, 80, -12, -102, 7, -106, -14, -18, -69, 34]
messageBytes: [-74, -125, 17, -98, 106, -83, -100, 29, 89, 70, -87, -122, -104, 84, 36, -34, 87, -111, 10, 13, -12, -112, -48, -90, 127, 75, 95, 64, 11, -96, 25, 26, 92, -111, 10, 6, 93, 36, -95, 127, -50, 65, 15, -111, -82, 48, 2, 94, 8, -6, -102, -96, -43, -110, -57, -26, -79, -42, -57, 121, -110, -74, -108, 17, 44, -28, -43, -96, 79, 60, -91, 23, -67, -76, 10, -1, -57, -11, 10, 114, -74, 107, -99, -83, 38, 109, 99, -13, 44, 102, 112, 74, -13, -84, 60, -101, -19, -78, -50, 29, 50, 105, -10, -103, -107, -47, -60, 78, 61, -35, -12, 114, -21, -34, -110, -103, -91, -70, -73, 0, 118, 45, 113, 40, 99, -76, -8, 126]

К сожалению, расшифрованные сообщенияBytes не совпадают с теми, которые были отправлены на карту.Почему-то дешифрование (на сервере) отличается от шифрования (на карте), но я не могу понять, почему и как.Моя конфигурация шифра на карте такая же, как и на сервере.

Обратите внимание, что я проверил правильность используемого сеансового ключа и IvParameters как на карте, так и на сервере.

Также обратите внимание, что я осведомлен о навязанных рисках безопасности, связанных с этим криптографическим кодом.

Обновление 1

Теперь, включая ключ сеанса в байтах.Кроме того, я обновил размер задачи до 32 байт (потому что после этого мне нужно снова зашифровать его с помощью AES).

Обновление 2

Теперь, включая весь код накарта для метода authenticateSP.

1 Ответ

0 голосов
/ 03 июня 2018

Нашел решение.Причина, по которой расшифрованные байты не были одинаковыми, состоит в том, что ключ сеанса на карте установлен с 256-битным (32-байтовым) массивом (KEYS_SESSION), в то время как я указал, что ключ AESkey должен быть собран с использованием 128-битного ключа.

...