package es.gob.jmulticard;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import javax.security.auth.callback.PasswordCallback;
import org.junit.Assert;
import org.junit.Test;
import org.spongycastle.jce.ECNamedCurveTable;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.jce.spec.ECParameterSpec;
import org.spongycastle.jce.spec.ECPrivateKeySpec;
import es.gob.jmulticard.CryptoHelper.EcCurve;
import es.gob.jmulticard.apdu.connection.ApduConnection;
import es.gob.jmulticard.card.CryptoCard;
import es.gob.jmulticard.card.dnie.DnieFactory;
import es.gob.jmulticard.jse.provider.JseCryptoHelper;
import es.gob.jmulticard.jse.smartcardio.SmartcardIoConnection;
/** pruebas de PACE con DNIe 3.0.
* @author Tomás García-Merás. */
public final class TestPaceDnie {
final static class CachePasswordCallback extends PasswordCallback {
private static final long serialVersionUID = 816457144215238935L;
/** Contruye una Callback con una contraseñ preestablecida.
* @param password Contraseña por defecto. */
public CachePasswordCallback(final char[] password) {
super(">", false); //$NON-NLS-1$
this.setPassword(password);
}
}
/** Main.
* @param args No se usa.
* @throws Exception En cualquier error. */
public static void main(final String[] args) throws Exception {
final ApduConnection conn = new SmartcardIoConnection();
final CachePasswordCallback cpc = new CachePasswordCallback("password".toCharArray()); //$NON-NLS-1$
CryptoCard dni = null;
try {
dni = DnieFactory.getDnie(
conn,
cpc,
new JseCryptoHelper(),
null
);
} catch (final Exception e) {
throw new Exception(e.getMessage());
}
System.out.println("Canal PACE abierto"); //$NON-NLS-1$
dni.changePIN("password", "1234512345"); //$NON-NLS-1$ //$NON-NLS-2$
System.out.println("Se ha realizado el cambio de PIN correctamente"); //$NON-NLS-1$
}
/** Prueba de cifrado AES según valores del manual.
* @throws Exception En cualquier error. */
@SuppressWarnings("static-method")
@Test
public void testAesDec() throws Exception {
final byte[] nonce = new byte[] {
(byte)0x39, (byte)0xe9, (byte)0x79, (byte)0xea, (byte)0x2c, (byte)0x87, (byte)0x25, (byte)0x4d,
(byte)0x98, (byte)0x86, (byte)0x1b, (byte)0x09, (byte)0x34, (byte)0x52, (byte)0x23, (byte)0xb4
};
final byte[] sk = new byte[] {
(byte)0x59, (byte)0x14, (byte)0x68, (byte)0xcd, (byte)0xa8, (byte)0x3d, (byte)0x65, (byte)0x21,
(byte)0x9c, (byte)0xcc, (byte)0xb8, (byte)0x56, (byte)0x02, (byte)0x33, (byte)0x60, (byte)0x0f
};
Assert.assertEquals(
"10EA7515CF362555AB77B7DCE0384E89", //$NON-NLS-1$
HexUtils.hexify(
new JseCryptoHelper().aesDecrypt(nonce, new byte[0], sk),
false
)
);
}
/** Prueba de DH-EC según valores del manual.
* @throws Exception En cualquier error. */
@SuppressWarnings("static-method")
@Test
public void testDhEc() throws Exception {
final byte[] prkIfcDh1 = new byte[] {
(byte)0x04,
(byte)0x93, (byte)0x6a, (byte)0x1f, (byte)0x95, (byte)0xb4, (byte)0x0e, (byte)0x4a, (byte)0xf3,
(byte)0xa2, (byte)0xb2, (byte)0xef, (byte)0x44, (byte)0xf2, (byte)0x31, (byte)0x09, (byte)0x50,
(byte)0x8c, (byte)0x7f, (byte)0x77, (byte)0x81, (byte)0xef, (byte)0x05, (byte)0xc8, (byte)0xf2,
(byte)0xf8, (byte)0x80, (byte)0xde, (byte)0x42, (byte)0xfa, (byte)0xb9, (byte)0xfb, (byte)0xa0,
(byte)0x1d, (byte)0x17, (byte)0xd9, (byte)0xef, (byte)0x41, (byte)0x73, (byte)0xb6, (byte)0xc1,
(byte)0xe6, (byte)0x23, (byte)0x01, (byte)0x9f, (byte)0x6f, (byte)0xd8, (byte)0x08, (byte)0x0b,
(byte)0xc9, (byte)0xdf, (byte)0x0f, (byte)0x71, (byte)0xbc, (byte)0xe1, (byte)0x8d, (byte)0x46,
(byte)0xb7, (byte)0x00, (byte)0xd0, (byte)0x5e, (byte)0x64, (byte)0x89, (byte)0x10, (byte)0xec
};
final byte[] pukIccDh1 = new byte[] {
(byte)0x04,
(byte)0x64, (byte)0x44, (byte)0x87, (byte)0x06, (byte)0x4b, (byte)0x4b, (byte)0x21, (byte)0x21,
(byte)0xd8, (byte)0xc7, (byte)0xe2, (byte)0x2b, (byte)0x27, (byte)0x8b, (byte)0x19, (byte)0x14,
(byte)0x33, (byte)0x51, (byte)0xe0, (byte)0xa7, (byte)0x4a, (byte)0x99, (byte)0xe9, (byte)0x8f,
(byte)0xc7, (byte)0x60, (byte)0xad, (byte)0x0a, (byte)0xc9, (byte)0x00, (byte)0xbc, (byte)0x27,
(byte)0x88, (byte)0x3e, (byte)0x8e, (byte)0xa2, (byte)0xef, (byte)0xcb, (byte)0xf3, (byte)0x02,
(byte)0xdc, (byte)0x7d, (byte)0x6a, (byte)0xcf, (byte)0x5d, (byte)0x6a, (byte)0xdc, (byte)0xd4,
(byte)0x64, (byte)0xbd, (byte)0x18, (byte)0x85, (byte)0xe6, (byte)0xe6, (byte)0x4f, (byte)0xf9,
(byte)0x45, (byte)0xe1, (byte)0xe8, (byte)0xb8, (byte)0x84, (byte)0x61, (byte)0x99, (byte)0xf7
};
final byte[] res = new JseCryptoHelper().doEcDh(
loadEcPrivateKey(prkIfcDh1, EcCurve.BRAINPOOL_P256_R1),
pukIccDh1,
EcCurve.BRAINPOOL_P256_R1
);
System.out.println(
HexUtils.hexify(
res,
false
)
);
System.out.println("Len: " + res.length); //$NON-NLS-1$
}
private static Key loadEcPrivateKey(final byte [] data, final EcCurve curveName) throws NoSuchAlgorithmException,
InvalidKeySpecException {
Security.addProvider(new BouncyCastleProvider());
final ECParameterSpec params = ECNamedCurveTable.getParameterSpec(curveName.toString());
final ECPrivateKeySpec prvkey = new ECPrivateKeySpec(new BigInteger(data), params);
KeyFactory kf;
try {
kf = KeyFactory.getInstance("ECDH", BouncyCastleProvider.PROVIDER_NAME); //$NON-NLS-1$
}
catch (final NoSuchProviderException e) {
kf = KeyFactory.getInstance("ECDH"); //$NON-NLS-1$
}
return kf.generatePrivate(prvkey);
}
}