com.licel.jcardsim.crypto.SymmetricCipherImplTest.java Source code

Java tutorial

Introduction

Here is the source code for com.licel.jcardsim.crypto.SymmetricCipherImplTest.java

Source

/*
 * Copyright 2011 Licel LLC.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.licel.jcardsim.crypto;

import javacard.framework.Util;
import javacard.security.AESKey;
import javacard.security.Key;
import javacard.security.KeyBuilder;
import javacardx.crypto.Cipher;
import junit.framework.TestCase;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;

/**
 * Test for
 * <code>SymmetricCipherImpl</code> Test data from NXP JCOP31-36 JavaCard
 */
public class SymmetricCipherImplTest extends TestCase {

    // padded etalon message
    String MESSAGE_8 = "C899464893435BC8";
    // etalon message without padding
    String MESSAGE_15 = "C46A3D01F5494013F9DFF3C5392C64";
    // etalon des key
    String DES_KEY = "71705866C930F0AE";
    // etalon 3des key
    String DES3_KEY = "B1891A49B2EA69F21245D4A51DD132E24F247FAC6D97F007";
    // etalon IV vector
    String IV = "F8D7DB2B902855A3";
    // MESSAGE_15 encrypted by card (DES key)
    String[] DES_ENCRYPTED_15 = new String[] {
            // ALG_DES_CBC_ISO9797_M1
            "F38F388669A566CC2CC3B23F98A404FE",
            // ALG_DES_CBC_ISO9797_M2
            "F38F388669A566CCD7863C7D58BD53F4",
            // ALG_DES_ECB_ISO9797_M1
            "F38F388669A566CCE9DE32BDE856B809",
            // ALG_DES_ECB_ISO9797_M2
            "F38F388669A566CCC0A527F4726E318D", };
    // MESSAGE_15 encrypted by card (3DES key)
    String[] DES3_ENCRYPTED_15 = new String[] {
            // ALG_DES_CBC_ISO9797_M1
            "59AEEAFA9FD22B2E165DD117D24198B1",
            // ALG_DES_CBC_ISO9797_M2
            "59AEEAFA9FD22B2EC8D247D6209E2E44",
            // ALG_DES_ECB_ISO9797_M1
            "59AEEAFA9FD22B2E6948896A7E159FAF",
            // ALG_DES_ECB_ISO9797_M2
            "59AEEAFA9FD22B2EDAA807A92435BB13", };
    // MESSAGE_15 encrypted by card (DES key) in CBC mode with non-zero IV
    String[] DES_ENCRYPTED_15_IV = new String[] {
            // ALG_DES_CBC_ISO9797_M1
            "302A9CDD30BC0F9286D64C88EFE70383",
            // ALG_DES_CBC_ISO9797_M2
            "302A9CDD30BC0F921B66F319FA735F75", };
    // MESSAGE_15 encrypted by card (3DES key) in CBC mode with non-zero IV
    String[] DES3_ENCRYPTED_15_IV = new String[] {
            // ALG_DES_CBC_ISO9797_M1
            "70A88CEADAD491A0CC4EBC98BFFFAC21",
            // ALG_DES_CBC_ISO9797_M2
            "70A88CEADAD491A0EC17707C14FA1344", };
    // MESSAGE_8 encrypted by card (DES key)
    String[] DES_ENCRYPTED_8 = new String[] {
            // ALG_DES_CBC_NOPAD
            "8E5ABFB9D5F015EE",
            // ALG_DES_ECB_NOPAD
            "8E5ABFB9D5F015EE" };
    // MESSAGE_8 encrypted by card (3DES key)
    String[] DES3_ENCRYPTED_8 = new String[] {
            // ALG_DES_CBC_NOPAD
            "DB3543BCBB4EAD86",
            // ALG_DES_ECB_NOPAD
            "DB3543BCBB4EAD86" };
    // MESSAGE_8 encrypted by card (DES key) in CBC mode with non-zero IV
    String[] DES_ENCRYPTED_8_IV = new String[] {
            // ALG_DES_CBC_NOPAD
            "3CE9E2657AFCE8B6" };
    // MESSAGE_8 encrypted by card (3DES key) in CBC mode with non-zero IV
    String[] DES3_ENCRYPTED_8_IV = new String[] {
            // ALG_DES_CBC_NOPAD
            "81B2369E2773858F" };
    // AES test data from NIST (sp800-38a)
    // FORMAT: key:[iv]:data:result
    // Appendix F.1
    String[] AES_ECB_128_TEST = { "2b7e151628aed2a6abf7158809cf4f3c", "6bc1bee22e409f96e93d7e117393172a",
            "3ad77bb40d7a3660a89ecaf32466ef97" };
    // Appendix F.1.3
    String[] AES_ECB_192_TEST = { "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
            "6bc1bee22e409f96e93d7e117393172a", "bd334f1d6e45f25ff712a214571fa5cc" };
    // Appendix F.1.5
    String[] AES_ECB_256_TEST = { "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
            "6bc1bee22e409f96e93d7e117393172a", "f3eed1bdb5d2a03c064b5a7e3db181f8" };
    // Appendix F.2.1
    String[] AES_CBC_128_TEST = { "2b7e151628aed2a6abf7158809cf4f3c", "000102030405060708090a0b0c0d0e0f",
            "6bc1bee22e409f96e93d7e117393172a", "7649abac8119b246cee98e9b12e9197d" };
    // Appendix F.2.3
    String[] AES_CBC_192_TEST = { "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
            "000102030405060708090a0b0c0d0e0f", "6bc1bee22e409f96e93d7e117393172a",
            "4f021db243bc633d7178183a9fa071e8" };
    // Appendix F.2.5
    String[] AES_CBC_256_TEST = { "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
            "000102030405060708090a0b0c0d0e0f", "6bc1bee22e409f96e93d7e117393172a",
            "f58c4c04d6e5f1ba779eabfb5f7bfbd6" };

    public SymmetricCipherImplTest(String testName) {
        super(testName);
    }

    protected void setUp() throws Exception {
        super.setUp();
    }

    protected void tearDown() throws Exception {
        super.tearDown();
    }

    /**
     * Test of doFinal method, of class SymmetricCipherImpl with 3DES Key
     */
    public void testDoFinal3DES() {
        SymmetricKeyImpl desKey = new SymmetricKeyImpl(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES3_3KEY);
        desKey.setKey(Hex.decode(DES3_KEY), (short) 0);
        testDoFinalDES(desKey, MESSAGE_8, MESSAGE_15, DES3_ENCRYPTED_8, DES3_ENCRYPTED_15, DES3_ENCRYPTED_8_IV,
                DES3_ENCRYPTED_15_IV);
    }

    /**
     * Test of doFinal method, of class SymmetricCipherImpl with DES Key
     */
    public void testDoFinalDES() {
        SymmetricKeyImpl desKey = new SymmetricKeyImpl(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES);
        desKey.setKey(Hex.decode(DES_KEY), (short) 0);
        testDoFinalDES(desKey, MESSAGE_8, MESSAGE_15, DES_ENCRYPTED_8, DES_ENCRYPTED_15, DES_ENCRYPTED_8_IV,
                DES_ENCRYPTED_15_IV);
    }

    /**
     * Test of doFinal method, of class SymmetricCipherImpl with specified key
     * and DES cipher
     */
    public void testDoFinalDES(SymmetricKeyImpl desKey, String msg8, String msg15, String[] enc8, String[] enc15,
            String[] enc8IV, String[] enc15IV) {
        // test DES CBC with IV={0,0,0,0,0,0,0,0}
        Cipher engine = Cipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
        testEngineDoFinal(engine, desKey, null, Hex.decode(msg8), Hex.decode(enc8[0]));

        engine = Cipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M1, false);
        testEngineDoFinal(engine, desKey, null, Hex.decode(msg15), Hex.decode(enc15[0]));

        engine = Cipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M2, false);
        testEngineDoFinal(engine, desKey, null, Hex.decode(msg15), Hex.decode(enc15[1]));

        // test DES CBC with non-zero IV
        byte[] iv = Hex.decode(IV);
        engine = Cipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
        testEngineDoFinal(engine, desKey, iv, Hex.decode(msg8), Hex.decode(enc8IV[0]));

        engine = Cipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M1, false);
        testEngineDoFinal(engine, desKey, iv, Hex.decode(msg15), Hex.decode(enc15IV[0]));

        engine = Cipher.getInstance(Cipher.ALG_DES_CBC_ISO9797_M2, false);
        testEngineDoFinal(engine, desKey, iv, Hex.decode(msg15), Hex.decode(enc15IV[1]));

        // test DES ECB
        engine = Cipher.getInstance(Cipher.ALG_DES_ECB_NOPAD, false);
        testEngineDoFinal(engine, desKey, null, Hex.decode(msg8), Hex.decode(enc8[1]));

        engine = Cipher.getInstance(Cipher.ALG_DES_ECB_ISO9797_M1, false);
        testEngineDoFinal(engine, desKey, null, Hex.decode(msg15), Hex.decode(enc15[2]));

        engine = Cipher.getInstance(Cipher.ALG_DES_ECB_ISO9797_M2, false);
        testEngineDoFinal(engine, desKey, null, Hex.decode(msg15), Hex.decode(enc15[3]));

    }

    public void testAes() {
        testAESMode(KeyBuilder.LENGTH_AES_128, Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, AES_ECB_128_TEST);
        testAESMode(KeyBuilder.LENGTH_AES_192, Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, AES_ECB_192_TEST);
        testAESMode(KeyBuilder.LENGTH_AES_256, Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, AES_ECB_256_TEST);
        testAESMode(KeyBuilder.LENGTH_AES_128, Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, AES_CBC_128_TEST);
        testAESMode(KeyBuilder.LENGTH_AES_192, Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, AES_CBC_192_TEST);
        testAESMode(KeyBuilder.LENGTH_AES_256, Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, AES_CBC_256_TEST);
    }

    /**
     * Test AES cipher mode
     */
    public void testAESMode(short keyLen, byte mode, String[] testData) {
        short keyLenInBytes = (short) (keyLen / 8);
        Cipher engine = Cipher.getInstance(mode, false);
        AESKey aesKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, keyLen, false);
        byte[] etalonKey = Hex.decode(testData[0]);
        byte[] key = new byte[keyLenInBytes];
        Util.arrayCopy(etalonKey, (short) 0, key, (short) 0, (short) etalonKey.length);
        aesKey.setKey(key, (short) 0);
        boolean needIV = (mode == Cipher.ALG_AES_BLOCK_128_CBC_NOPAD);
        if (needIV) {
            byte[] iv = Hex.decode(testData[1]);
            engine.init(aesKey, Cipher.MODE_ENCRYPT, iv, (short) 0, (short) iv.length);
        } else {
            engine.init(aesKey, Cipher.MODE_ENCRYPT);
        }
        byte[] encrypted = new byte[16]; // AES 128
        short processedBytes = engine.doFinal(Hex.decode(testData[needIV ? 2 : 1]), (short) 0, (short) 16,
                encrypted, (short) 0);
        assertEquals(processedBytes, 16);
        assertEquals(true, Arrays.areEqual(encrypted, Hex.decode(testData[needIV ? 3 : 2])));
        if (needIV) {
            byte[] iv = Hex.decode(testData[1]);
            engine.init(aesKey, Cipher.MODE_DECRYPT, iv, (short) 0, (short) iv.length);
        } else {
            engine.init(aesKey, Cipher.MODE_DECRYPT);
        }
        byte[] decrypted = new byte[16]; // AES 128
        processedBytes = engine.doFinal(Hex.decode(testData[needIV ? 3 : 2]), (short) 0, (short) 16, decrypted,
                (short) 0);
        assertEquals(processedBytes, 16);
        assertEquals(true, Arrays.areEqual(decrypted, Hex.decode(testData[needIV ? 2 : 1])));
    }

    /**
     * Test method
     * <code>doFinal</code>
     *
     * @param engine test engine
     * @param key etalon key
     * @param iv IV if present
     * @param msg etalon message
     * @param encryptedEtalonMsg encrypted etalon message
     */
    public void testEngineDoFinal(Cipher engine, Key key, byte[] iv, byte[] msg, byte[] encryptedEtalonMsg) {
        // first test equals encryption
        if (iv == null) {
            engine.init(key, Cipher.MODE_ENCRYPT);
        } else {
            engine.init(key, Cipher.MODE_ENCRYPT, iv, (short) 0, (short) iv.length);
        }
        byte[] encrypted = new byte[encryptedEtalonMsg.length];
        short processedBytes = engine.doFinal(msg, (short) 0, (short) msg.length, encrypted, (short) 0);
        assertEquals(true, Arrays.areEqual(encrypted, encryptedEtalonMsg));
        assertEquals(processedBytes, encryptedEtalonMsg.length);
        // second test decryption
        if (iv == null) {
            engine.init(key, Cipher.MODE_DECRYPT);
        } else {
            engine.init(key, Cipher.MODE_DECRYPT, iv, (short) 0, (short) iv.length);
        }
        byte[] decrypted = new byte[msg.length];
        processedBytes = engine.doFinal(encryptedEtalonMsg, (short) 0, (short) encryptedEtalonMsg.length, decrypted,
                (short) 0);
        assertEquals(processedBytes, msg.length);
        assertEquals(true, Arrays.areEqual(decrypted, msg));
    }
}