/*
* 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 java.security.SecureRandom;
import javacard.security.MessageDigest;
import junit.framework.TestCase;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
/**
* Test for <code>MessageDigestImpl</code>
* Test data from NXP JCOP31-36 JavaCard
*/
public class MessageDigestImplTest extends TestCase {
static final String MESSAGE1 = "F9607F6E66B4162C";
static final String MESSAGE2 = "26C69FC4C14399A399B5B28AD9CC5B91796BC2565C5580BAC1BE10808F71949D8B";
// card response with algorithm MD5
static final String MD_1_NXP_MD5 = "3A43CC845A3DF85404A97407877D3A77";
static final String MD_2_NXP_MD5 = "5919172BA50F4944339260067E09387A";
// card response with algorithm SHA1
static final String MD_1_NXP_SHA1 = "94FF92DC796929290990BA74F4B125F04F9B510A";
static final String MD_2_NXP_SHA1 = "01793FF98B954C3F60F276B179186C499F619A9D";
// card response with algorithm SHA256
static final String MD_1_NXP_SHA256 = "E700E0E6E5A4F3FF05CCBD4DA9CDBBEC712189DE65EF1ED19C351F7966270EF0";
static final String MD_2_NXP_SHA256 = "17CB067C5E384B85DF370B96A5C91817D908F0C760CB2D7539EF8B9A7C02AB80";
// NIST SHA-384 SHA ETALON MESSAGES
static final String MESSAGE_64_NIST_SHA384 = "DE60275BDAFCE4B1";
static final String MESSAGE_256_NIST_SHA384 = "BE01E520E69F04174CCF95455B1C81445298264D9ADC4958574A52843D95B8BA";
// NIST SHA-384 ETALON DIGESTS
static final String MD_64_NIST_SHA384 = "A3D861D866C1362423EB21C6BEC8E44B74CE993C55BAA2B6640567560EBECDAEDA07183DBBBD95E0F522CAEE5DDBDAF0";
static final String MD_256_NIST_SHA384 = "C5CF54B8E3105B1C7BF7A43754D915B0947F28B6DC94A019182929B5C848E11441C9E4E90C7449F4C3CD12954F0F5D99";
// NIST SHA-512 ETALON MESSAGES
static final String MESSAGE_64_NIST_SHA512 = "6F8D58B7CAB1888C";
static final String MESSAGE_256_NIST_SHA512 = "8CCB08D2A1A282AA8CC99902ECAF0F67A9F21CFFE28005CB27FCF129E963F99D";
// NIST SHA-512 ETALON DIGESTS
static final String MD_64_NIST_SHA512 = "A3941DEF2803C8DFC08F20C06BA7E9A332AE0C67E47AE57365C243EF40059B11BE22C91DA6A80C2CFF0742A8F4BCD941BDEE0B861EC872B215433CE8DCF3C031";
static final String MD_256_NIST_SHA512 = "4551DEF2F9127386EEA8D4DAE1EA8D8E49B2ADD0509F27CCBCE7D9E950AC7DB01D5BCA579C271B9F2D806730D88F58252FD0C2587851C3AC8A0E72B4E1DC0DA6";
MessageDigestImpl engineMD5 = new MessageDigestImpl(MessageDigest.ALG_MD5);
MessageDigestImpl engineRIPEMD160 = new MessageDigestImpl(MessageDigest.ALG_RIPEMD160);
MessageDigestImpl engineSHA1 = new MessageDigestImpl(MessageDigest.ALG_SHA);
MessageDigestImpl engineSHA256 = new MessageDigestImpl(MessageDigest.ALG_SHA_256);
MessageDigestImpl engineSHA384 = new MessageDigestImpl(MessageDigest.ALG_SHA_384);
MessageDigestImpl engineSHA512 = new MessageDigestImpl(MessageDigest.ALG_SHA_512);
SecureRandom rnd = new SecureRandom();
public MessageDigestImplTest(String testName) {
super(testName);
}
protected void setUp() throws Exception {
super.setUp();
}
protected void tearDown() throws Exception {
super.tearDown();
}
/**
* Test of getAlgorithm method, of class MessageDigestImpl.
*/
public void testGetAlgorithm() {
System.out.println("getAlgorithm");
// md5
byte expResult = MessageDigest.ALG_MD5;
byte result = engineMD5.getAlgorithm();
assertEquals(expResult, result);
// sha1
expResult = MessageDigest.ALG_SHA;
result = engineSHA1.getAlgorithm();
assertEquals(expResult, result);
// sha256
expResult = MessageDigest.ALG_SHA_256;
result = engineSHA256.getAlgorithm();
assertEquals(expResult, result);
// sha384
expResult = MessageDigest.ALG_SHA_384;
result = engineSHA384.getAlgorithm();
assertEquals(expResult, result);
// sha512
expResult = MessageDigest.ALG_SHA_512;
result = engineSHA512.getAlgorithm();
assertEquals(expResult, result);
}
/**
* Test of getLength method, of class MessageDigestImpl.
*/
public void testGetLength() {
System.out.println("getLength");
// md5
assertEquals(engineMD5.getLength(), MessageDigest.LENGTH_MD5);
// ripemd160
assertEquals(engineRIPEMD160.getLength(), MessageDigest.LENGTH_RIPEMD160);
// sha1
assertEquals(engineSHA1.getLength(), MessageDigest.LENGTH_SHA);
// sha256
assertEquals(engineSHA256.getLength(), MessageDigest.LENGTH_SHA_256);
// sha384
assertEquals(engineSHA384.getLength(), MessageDigest.LENGTH_SHA_384);
// sha512
assertEquals(engineSHA512.getLength(), MessageDigest.LENGTH_SHA_512);
}
/**
* Test MD5 algorithm with card response
*/
public void testMD5() {
System.out.println("test MD5 doFinal()");
testEngineDoFinal(engineMD5, Hex.decode(MESSAGE1), Hex.decode(MD_1_NXP_MD5));
System.out.println("test MD5 doUpdate() + doFinal()");
testEngineDoUpdateFinal(engineMD5, Hex.decode(MESSAGE2), Hex.decode(MD_2_NXP_MD5));
}
/**
* Test SHA1 algorithm with card response
*/
public void testSHA() {
System.out.println("test SHA1 doFinal()");
testEngineDoFinal(engineSHA1, Hex.decode(MESSAGE1), Hex.decode(MD_1_NXP_SHA1));
System.out.println("test SHA1 doUpdate() + doFinal()");
testEngineDoUpdateFinal(engineSHA1, Hex.decode(MESSAGE2), Hex.decode(MD_2_NXP_SHA1));
}
/**
* Test SHA256 algorithm with card response
*/
public void testSHA256() {
System.out.println("test SHA256 doFinal()");
testEngineDoFinal(engineSHA256, Hex.decode(MESSAGE1), Hex.decode(MD_1_NXP_SHA256));
System.out.println("test SHA256 doUpdate() + doFinal()");
testEngineDoUpdateFinal(engineSHA256, Hex.decode(MESSAGE2), Hex.decode(MD_2_NXP_SHA256));
}
/**
* Test SHA384 algorithm with card response
*/
public void testSHA384() {
System.out.println("test SHA384 doFinal()");
testEngineDoFinal(engineSHA384, Hex.decode(MESSAGE_64_NIST_SHA384), Hex.decode(MD_64_NIST_SHA384));
System.out.println("test SHA384 doUpdate() + doFinal()");
testEngineDoUpdateFinal(engineSHA384, Hex.decode(MESSAGE_256_NIST_SHA384), Hex.decode(MD_256_NIST_SHA384));
}
/**
* Test SHA512 algorithm with card response
*/
public void testSHA512() {
System.out.println("test SHA512 doFinal()");
testEngineDoFinal(engineSHA512, Hex.decode(MESSAGE_64_NIST_SHA512), Hex.decode(MD_64_NIST_SHA512));
System.out.println("test SHA512 doUpdate() + doFinal()");
testEngineDoUpdateFinal(engineSHA512, Hex.decode(MESSAGE_256_NIST_SHA512), Hex.decode(MD_256_NIST_SHA512));
}
/**
* Test method <code>doFinal</code>
* @param engine tested engine
* @param msg byte array contains etalon message
* @param etalonDigest byte array contains etalon digest
*/
public void testEngineDoFinal(MessageDigest engine, byte[] msg, byte[] etalonDigest) {
byte[] digest = new byte[engine.getLength()];
engine.doFinal(msg, (short) 0, (short) msg.length, digest, (short) 0);
assertEquals(true, Arrays.areEqual(etalonDigest, digest));
}
/**
* Test sequence method's calls <code>doUpdate();doFinal()</code>
* @param engine tested engine
* @param msg byte array contains etalon message
* @param etalonDigest byte array contains etalon digest
*/
public void testEngineDoUpdateFinal(MessageDigest engine, byte[] msg, byte[] etalonDigest) {
byte[] digest = new byte[engine.getLength()];
engine.update(msg, (short) 0, (short) 7);
engine.doFinal(msg, (short) 7, (short) (msg.length - 7), digest, (short) 0);
assertEquals(true, Arrays.areEqual(etalonDigest, digest));
}
/**
* Test of setInitialDigest method, of class MessageDigestImpl.
*/
public void testSetInitialDigest() {
byte[] initialDigestBuf = new byte[128];
byte[] inputData = new byte[254];
rnd.nextBytes(inputData);
MessageDigestImpl[] digests = new MessageDigestImpl[]{engineSHA1, engineMD5, engineRIPEMD160,
engineSHA256, engineSHA384, engineSHA512};
for (short i = 0; i < digests.length; i++) {
System.out.println("testSetInitialDigest() - "+digests[i].getAlgorithm());
byte[] digest = new byte[digests[i].getLength()];
byte[] etalonDigest = new byte[digests[i].getLength()];
// calc first part
short part = digests[i].getBlockSize();
digests[i].update(inputData, (short) 0, part);
short initialDigestOff = (short) rnd.nextInt(initialDigestBuf.length - digests[i].getLength());
digests[i].getIntermediateDigest(initialDigestBuf, initialDigestOff);
// doFinal
digests[i].doFinal(inputData, part, (short) (inputData.length - part), digest, (short) 0);
// etalon
digests[i].reset();
digests[i].update(inputData, (short) 0, part);
digests[i].doFinal(inputData, part, (short) (inputData.length - part), etalonDigest, (short) 0);
assertEquals(true, Arrays.areEqual(etalonDigest, digest));
}
}
}