/** * Java Card implementation of the OpenPGP card * Copyright (C) 2011 Joeri de Ruiter <joeri@cs.ru.nl> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package openpgpcard; import javacard.framework.*; import javacard.security.*; public class PGPKey implements ISO7816 { public static final short KEY_SIZE = 2048;// 2368; public static final short KEY_SIZE_BYTES = KEY_SIZE / 8; public static final short COMPONENT_BYTES = KEY_SIZE_BYTES / 2; public static final short EXPONENT_SIZE = 17; public static final short EXPONENT_SIZE_BYTES = 3; public static final short FP_SIZE = 20; private KeyPair key; private byte[] fp; private byte[] time = { 0x00, 0x00, 0x00, 0x00 }; private byte[] attributes = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x03 }; private static byte[] tmpBuf; public PGPKey() { key = new KeyPair(KeyPair.ALG_RSA_CRT, KEY_SIZE); fp = new byte[FP_SIZE]; Util.arrayFillNonAtomic(fp, (short) 0, (short) fp.length, (byte) 0); Util.setShort(attributes, (short) 1, KEY_SIZE); Util.setShort(attributes, (short) 3, EXPONENT_SIZE); if(tmpBuf == null) { tmpBuf = JCSystem.makeTransientByteArray((short) (KEY_SIZE_BYTES / 2), JCSystem.CLEAR_ON_DESELECT); } } /** * Generate the key pair. */ public void genKeyPair() { key.genKeyPair(); } /** * Set the fingerprint for the public key. * * @param data * Byte array * @param offset * Offset within byte array containing first byte */ public void setFingerprint(byte[] data, short offset) { // Check whether there are enough bytes to copy if ((short) (offset + fp.length) > data.length) ISOException.throwIt(SW_UNKNOWN); Util.arrayCopyNonAtomic(data, offset, fp, (short) 0, (short) fp.length); } /** * Set the generation time for the key pair. * * @param data * Byte array * @param offset * Offset within byte array containing first byte */ public void setTime(byte[] data, short offset) { // Check whether there are enough bytes to copy if ((short) (offset + time.length) > data.length) ISOException.throwIt(SW_UNKNOWN); Util.arrayCopyNonAtomic(data, offset, time, (short) 0, (short) 4); } /** * Get the fingerprint for the public key. * * @param data * Byte array * @param offset * Offset within byte array indicating first byte */ public short getFingerprint(byte[] data, short offset) { Util.arrayCopyNonAtomic(fp, (short) 0, data, offset, (short) fp.length); return (short) (offset + fp.length); } /** * Get the generation time for the key pair. * * @param data * Byte array * @param offset * Offset within byte array indicating first byte */ public short getTime(byte[] data, short offset) { Util.arrayCopyNonAtomic(time, (short) 0, data, offset, (short) time.length); return (short) (offset + time.length); } /** * Get the algorithm attributes for the key pair. * * @param data * Byte array * @param offset * Offset within byte array indicating first byte */ public short getAttributes(byte[] data, short offset) { Util.arrayCopyNonAtomic(attributes, (short) 0, data, offset, (short) attributes.length); return (short) (offset + attributes.length); } /** * @return Public key of the key pair */ public RSAPublicKey getPublic() { return (RSAPublicKey) key.getPublic(); } /** * @return Private key of the key pair */ public RSAPrivateCrtKey getPrivate() { return (RSAPrivateCrtKey) key.getPrivate(); } /** * @return Length in bytes of the exponent */ public short getExponentLength() { // Fixed value of 65537 for exponent return EXPONENT_SIZE_BYTES; } /** * @return Length in bytes of the modulus */ public short getModulusLength() { return KEY_SIZE_BYTES; } /** * Sets the value of the DP1 parameter. The plain text data format is * big-endian and right-aligned (the least significant bit is the least * significant bit of last byte). Input DP1 parameter data is copied into * the internal representation. * * @param buffer * The input buffer * @param offset * The offset into the input buffer at which the parameter value * begins * @param length * The length of the parameter */ public void setDP1(byte[] buffer, short offset, short length) { Util.arrayFillNonAtomic(tmpBuf, (short) 0, (short) tmpBuf.length, (byte) 0); Util.arrayCopyNonAtomic(buffer, offset, tmpBuf, (short) (COMPONENT_BYTES - length), length); ((RSAPrivateCrtKey) key.getPrivate()).setDP1(tmpBuf, (short) 0, COMPONENT_BYTES); } /** * Sets the value of the DQ1 parameter. The plain text data format is * big-endian and right-aligned (the least significant bit is the least * significant bit of last byte). Input DQ1 parameter data is copied into * the internal representation. * * @param buffer * The input buffer * @param offset * The offset into the input buffer at which the parameter value * begins * @param length * The length of the parameter */ public void setDQ1(byte[] buffer, short offset, short length) { Util.arrayFillNonAtomic(tmpBuf, (short) 0, (short) tmpBuf.length, (byte) 0); Util.arrayCopyNonAtomic(buffer, offset, tmpBuf, (short) (COMPONENT_BYTES - length), length); ((RSAPrivateCrtKey) key.getPrivate()).setDQ1(tmpBuf, (short) 0, COMPONENT_BYTES); } /** * Sets the value of the P parameter. The plain text data format is * big-endian and right-aligned (the least significant bit is the least * significant bit of last byte). Input P parameter data is copied into the * internal representation. * * @param buffer * The input buffer * @param offset * The offset into the input buffer at which the parameter value * begins * @param length * The length of the parameter */ public void setP(byte[] buffer, short offset, short length) { ((RSAPrivateCrtKey) key.getPrivate()).setP(buffer, offset, length); } /** * Sets the value of the PQ parameter. The plain text data format is * big-endian and right-aligned (the least significant bit is the least * significant bit of last byte). Input PQ parameter data is copied into the * internal representation. * * @param buffer * The input buffer * @param offset * The offset into the input buffer at which the parameter value * begins * @param length * The length of the parameter */ public void setPQ(byte[] buffer, short offset, short length) { Util.arrayFillNonAtomic(tmpBuf, (short) 0, (short) tmpBuf.length, (byte) 0); Util.arrayCopyNonAtomic(buffer, offset, tmpBuf, (short) (COMPONENT_BYTES - length), length); ((RSAPrivateCrtKey) key.getPrivate()).setPQ(tmpBuf, (short) 0, COMPONENT_BYTES); } /** * Sets the value of the Q parameter. The plain text data format is * big-endian and right-aligned (the least significant bit is the least * significant bit of last byte). Input Q parameter data is copied into the * internal representation. * * @param buffer * The input buffer * @param offset * The offset into the input buffer at which the parameter value * begins * @param length * The length of the parameter */ public void setQ(byte[] buffer, short offset, short length) { ((RSAPrivateCrtKey) key.getPrivate()).setQ(buffer, offset, length); } /** * Sets the value of the Exponent parameter. The plain text data format is * big-endian and right-aligned (the least significant bit is the least * significant bit of last byte). Input Exponent parameter data is copied * into the internal representation. * * @param buffer * The input buffer * @param offset * The offset into the input buffer at which the parameter value * begins * @param length * The length of the parameter */ public void setExponent(byte[] buffer, short offset, short length) { ((RSAPublicKey) key.getPublic()).setExponent(buffer, offset, length); } /** * Sets the value of the Modulus parameter. The plain text data format is * big-endian and right-aligned (the least significant bit is the least * significant bit of last byte). Input Modulus parameter data is copied * into the internal representation. * * @param buffer * The input buffer * @param offset * The offset into the input buffer at which the parameter value * begins * @param length * The length of the parameter */ public void setModulus(byte[] buffer, short offset, short length) { ((RSAPublicKey) key.getPublic()).setModulus(buffer, offset, length); } }