/* * 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)); } }