Initial commit

This commit is contained in:
Arnaud Fontaine
2016-10-21 14:56:47 +02:00
commit 6635448be6
28 changed files with 10334 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
/*
SmartPGP : JavaCard implementation of OpenPGP card v3 specification
https://github.com/ANSSI-FR/smartpgp
Copyright (C) 2016 ANSSI
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 fr.anssi.smartpgp;
import javacard.framework.*;
import javacard.security.*;
import javacardx.apdu.*;
import javacardx.crypto.*;
public final class CmacKey {
protected final AESKey key;
protected final byte[] k1;
protected final byte[] k2;
protected CmacKey() {
key = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT,
(short)(Constants.aesKeyLength() * 8),
false);
k1 = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE, JCSystem.CLEAR_ON_DESELECT);
k2 = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE, JCSystem.CLEAR_ON_DESELECT);
}
protected final boolean isInitialized() {
return key.isInitialized();
}
protected final void clearKey() {
key.clearKey();
Util.arrayFillNonAtomic(k1, (short)0, (short)k1.length, (byte)0);
Util.arrayFillNonAtomic(k2, (short)0, (short)k2.length, (byte)0);
}
protected final void setKey(final byte[] buf, final short bufOff) {
key.setKey(buf, bufOff);
final Cipher cipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
cipher.init(key, Cipher.MODE_ENCRYPT);
Util.arrayFillNonAtomic(k2, (short)0, Constants.AES_BLOCK_SIZE, (byte)0);
cipher.doFinal(k2, (short)0, Constants.AES_BLOCK_SIZE,
k1, (short)0);
final boolean mark = ((k1[0] & (byte)0x80) != (byte)0);
Common.arrayLeftShift(k1, (short)0,
k1, (short)0,
Constants.AES_BLOCK_SIZE);
if(mark) {
k1[(short)(Constants.AES_BLOCK_SIZE - 1)] = (byte)(k1[(short)(Constants.AES_BLOCK_SIZE - 1)] ^ (byte)0x87);
}
Common.arrayLeftShift(k1, (short)0,
k2, (short)0,
Constants.AES_BLOCK_SIZE);
if((k1[0] & (byte)0x80) != (byte)0) {
k2[(short)(Constants.AES_BLOCK_SIZE - 1)] = (byte)(k2[(short)(Constants.AES_BLOCK_SIZE - 1)] ^ (byte)0x87);
}
}
}

View File

@@ -0,0 +1,229 @@
/*
SmartPGP : JavaCard implementation of OpenPGP card v3 specification
https://github.com/ANSSI-FR/smartpgp
Copyright (C) 2016 ANSSI
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 fr.anssi.smartpgp;
import javacard.framework.*;
import javacard.security.*;
import javacardx.apdu.*;
import javacardx.crypto.*;
public final class CmacSignature {
private CmacKey key;
private final Cipher cipher;
private final byte[] block_prev;
private final byte[] block;
private final byte[] bytes;
private static final byte BYTE_OFFSET_BLOCK_LEN = 0;
private static final byte BYTES_SIZE = BYTE_OFFSET_BLOCK_LEN + 1;
protected CmacSignature() {
key = null;
cipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
block_prev = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE, JCSystem.CLEAR_ON_DESELECT);
block = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE, JCSystem.CLEAR_ON_DESELECT);
bytes = JCSystem.makeTransientByteArray(BYTES_SIZE, JCSystem.CLEAR_ON_DESELECT);
}
protected final void clear() {
key = null;
}
private final byte blockLen() {
return bytes[BYTE_OFFSET_BLOCK_LEN];
}
private final void setBlockLen(final byte len) {
bytes[BYTE_OFFSET_BLOCK_LEN] = len;
}
protected final boolean isInitialized() {
return (key != null)
&& key.isInitialized();
}
private final void initBlock() {
Util.arrayFillNonAtomic(block_prev, (short)0, (short)block_prev.length, (byte)0);
Util.arrayFillNonAtomic(block, (short)0, (short)block.length, (byte)0);
Util.arrayFillNonAtomic(bytes, (short)0, (short)bytes.length, (byte)0);
}
protected final void init(final CmacKey key) {
if((key == null) || !key.isInitialized()) {
CryptoException.throwIt(CryptoException.UNINITIALIZED_KEY);
return;
}
this.key = key;
cipher.init(key.key, Cipher.MODE_ENCRYPT);
initBlock();
}
private final void commitBlock() {
setBlockLen((byte)0);
Common.arrayXor(block_prev, (short)0,
block, (short)0,
block, (short)0,
Constants.AES_BLOCK_SIZE);
cipher.doFinal(block, (short)0, Constants.AES_BLOCK_SIZE,
block_prev, (short)0);
}
protected final void update(final byte[] inBuf, short inOff, short inLen) {
if(!isInitialized()) {
CryptoException.throwIt(CryptoException.INVALID_INIT);
return;
}
if(inLen <= 0) {
return;
}
short bl = (short)blockLen();
short remLen = (short)(Constants.AES_BLOCK_SIZE - bl);
while(inLen >= remLen) {
Util.arrayCopyNonAtomic(inBuf, inOff,
block, bl,
remLen);
commitBlock();
inLen -= remLen;
inOff += remLen;
remLen = Constants.AES_BLOCK_SIZE;
bl = (short)0;
}
if(inLen > 0) {
Util.arrayCopyNonAtomic(inBuf, inOff,
block, bl,
inLen);
bl = (short)(bl + inLen);
}
setBlockLen((byte)bl);
}
protected final void updateByte(final byte b) {
if(!isInitialized()) {
CryptoException.throwIt(CryptoException.INVALID_INIT);
return;
}
short bl = blockLen();
block[bl++] = b;
if(bl == Constants.AES_BLOCK_SIZE) {
commitBlock();
} else {
setBlockLen((byte)bl);
}
}
protected final void updateShort(final short s) {
updateByte((byte)((s >> 8) & (byte)0xff));
updateByte((byte)(s & (byte)0xff));
}
private final void compute(final byte[] inBuf, short inOff, short inLen) {
if(!isInitialized()) {
CryptoException.throwIt(CryptoException.INVALID_INIT);
return;
}
if(inLen < 0) {
CryptoException.throwIt(CryptoException.ILLEGAL_USE);
return;
}
short bl = blockLen();
if(inLen > 0) {
final short il = (short)(inLen - 1);
update(inBuf, inOff, il);
bl = blockLen();
block[bl++] = inBuf[(short)(inOff + il)];
setBlockLen((byte)bl);
}
if(bl == Constants.AES_BLOCK_SIZE) {
Common.arrayXor(key.k1, (short)0,
block, (short)0,
block, (short)0,
Constants.AES_BLOCK_SIZE);
} else {
block[bl++] = (byte)0x80;
Util.arrayFillNonAtomic(block, bl, (short)(Constants.AES_BLOCK_SIZE - bl), (byte)0);
Common.arrayXor(key.k2, (short)0,
block, (short)0,
block, (short)0,
Constants.AES_BLOCK_SIZE);
}
commitBlock();
}
protected final short sign(final byte[] inBuf, short inOff, short inLen,
final byte[] sigBuf, final short sigOff, final short sigLen) {
if(!isInitialized()) {
CryptoException.throwIt(CryptoException.INVALID_INIT);
return 0;
}
if((sigLen < 0) || (sigLen > Constants.AES_BLOCK_SIZE)) {
CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
return 0;
}
compute(inBuf, inOff, inLen);
Util.arrayCopyNonAtomic(block_prev, (short)0,
sigBuf, sigOff,
sigLen);
init(key);
return sigLen;
}
}

View File

@@ -0,0 +1,138 @@
/*
SmartPGP : JavaCard implementation of OpenPGP card v3 specification
https://github.com/ANSSI-FR/smartpgp
Copyright (C) 2016 ANSSI
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 fr.anssi.smartpgp;
import javacard.framework.*;
import javacard.security.*;
import javacardx.apdu.*;
import javacardx.crypto.*;
public final class Common {
protected static final short writeLength(final byte[] buf, short off, final short len) {
if(len > 0xff) {
buf[off] = (byte)0x82;
return Util.setShort(buf, (short)(off+1), len);
}
if(len > 0x7f) {
buf[off++] = (byte)0x81;
buf[off++] = (byte)(len & 0xff);
return off;
}
buf[off++] = (byte)(len & 0x7f);
return off;
}
protected static final short skipLength(final byte[] buf, final short off, final short len) {
if(len < 1) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return off;
}
if((buf[off] & (byte)0x80) == 0) {
return (short)(off + 1);
}
switch(buf[off]) {
case (byte)0x81:
if(len < 2) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return off;
}
return (short)(off + 2);
case (byte)0x82:
if(len < 3) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return off;
}
return (short)(off + 3);
default:
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return off;
}
}
protected static final short readLength(final byte[] buf, final short off, final short len) {
if(len < 1) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return (short)0;
}
if((buf[off] & (byte)0x80) == 0) {
return Util.makeShort((byte)0, buf[off]);
}
switch(buf[off]) {
case (byte)0x81:
if(len < 2) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return (short)0;
}
return Util.makeShort((byte)0, buf[(short)(off + 1)]);
case (byte)0x82:
if(len < 3) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return (short)0;
}
return Util.getShort(buf, (short)(off + 1));
default:
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return (short)0;
}
}
protected static final short bitsToBytes(final short bits) {
return (short)((bits / 8) + (short)(((bits % 8) == 0) ? 0 : 1));
}
protected static final void arrayLeftShift(final byte[] inBuf, short inOff,
final byte[] outBuf, short outOff,
final short len) {
if(len > 0) {
outBuf[outOff++] = (byte)(inBuf[inOff++] << 1);
for(short i = 1; i < len; ++i) {
if((inBuf[inOff] & (byte)0x80) != (byte)0) {
outBuf[(short)(outOff - 1)] |= (byte)0x01;
}
outBuf[outOff++] = (byte)(inBuf[inOff++] << 1);
}
}
}
protected static final void arrayXor(final byte[] inBuf1, short inOff1,
final byte[] inBuf2, short inOff2,
final byte[] outBuf, short outOff,
final short len) {
for(short i = 0; i < len; ++i) {
outBuf[outOff++] = (byte)(inBuf1[inOff1++] ^ inBuf2[inOff2++]);
}
}
}

View File

@@ -0,0 +1,240 @@
/*
SmartPGP : JavaCard implementation of OpenPGP card v3 specification
https://github.com/ANSSI-FR/smartpgp
Copyright (C) 2016 ANSSI
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 fr.anssi.smartpgp;
import javacard.framework.*;
import javacard.security.*;
import javacardx.apdu.*;
import javacardx.crypto.*;
public final class Constants {
protected static final short INTERNAL_BUFFER_MAX_LENGTH =
(short)((short)0x500);
protected static final short APDU_MAX_LENGTH = (short)256;
protected static final byte USER_PIN_RETRY_COUNT = 3;
protected static final byte USER_PIN_MIN_SIZE = 0x06;
protected static final byte USER_PIN_MAX_SIZE = 0x7f; /* max is 0x7f because PIN format 2 */
protected static final byte[] USER_PIN_DEFAULT = {
0x31, 0x32, 0x33,0x34, 0x35, 0x36
};
protected static final boolean USER_PIN_DEFAULT_FORCE_VERIFY_SIGNATURE = true;
protected static final byte USER_PUK_RETRY_COUNT = 3;
protected static final byte USER_PUK_MIN_SIZE = 0x08;
protected static final byte USER_PUK_MAX_SIZE = 0x7f; /* max is 0x7f because PIN format 2 */
protected static final byte ADMIN_PIN_RETRY_COUNT = 3;
protected static final byte ADMIN_PIN_MIN_SIZE = 0x08;
protected static final byte ADMIN_PIN_MAX_SIZE = 0x7f; /* max is 0x7f because PIN format 2 */
protected static final byte[] ADMIN_PIN_DEFAULT = {
0x31, 0x32, 0x33,0x34, 0x35, 0x36, 0x37, 0x38
};
protected static final byte FINGERPRINT_SIZE = 20;
protected static final byte GENERATION_DATE_SIZE = 4;
protected static final byte NAME_MAX_LENGTH = 39;
protected static final byte LANG_MIN_LENGTH = 2;
protected static final byte LANG_MAX_LENGTH = 8;
protected static final byte[] LANG_DEFAULT = { (byte)0x65, (byte)0x6e };
protected static final byte SEX_MALE = (byte)0x31;
protected static final byte SEX_FEMALE = (byte)0x32;
protected static final byte SEX_NOT_ANNOUNCED = (byte)0x39;
protected static final short TAG_AID = (short)0x004f;
protected static final short TAG_LOGIN = (short)0x005e;
protected static final short TAG_URL = (short)0x5f50;
protected static final short TAG_HISTORICAL_BYTES_CARD_SERVICE_CARD_CAPABILITIES = (short)0x5f52;
protected static final short TAG_CARDHOLDER_RELATED_DATA = (short)0x0065;
protected static final short TAG_APPLICATION_RELATED_DATA = (short)0x006e;
protected static final short TAG_SECURITY_SUPPORT_TEMPLATE = (short)0x007a;
protected static final short TAG_CARDHOLDER_CERTIFICATE = (short)0x7f21;
protected static final short TAG_NAME = (short)0x005b;
protected static final short TAG_LANG = (short)0x5f2d;
protected static final short TAG_SEX = (short)0x5f35;
protected static final short TAG_ALGORITHM_ATTRIBUTES_SIG = (short)0x00c1;
protected static final short TAG_ALGORITHM_ATTRIBUTES_DEC = (short)0x00c2;
protected static final short TAG_ALGORITHM_ATTRIBUTES_AUT = (short)0x00c3;
protected static final short TAG_ALGORITHM_ATTRIBUTES_SM = (short)0x00d4;
protected static final short TAG_PW_STATUS = (short)0x00c4;
protected static final short TAG_KEY_FINGERPRINTS = (short)0x00c5;
protected static final short TAG_CA_FINGERPRINTS = (short)0x00c6;
protected static final short TAG_FINGERPRINT_SIG = (short)0x00c7;
protected static final short TAG_FINGERPRINT_DEC = (short)0x00c8;
protected static final short TAG_FINGERPRINT_AUT = (short)0x00c9;
protected static final short TAG_FINGERPRINT_CA = (short)0x00ca;
protected static final short TAG_FINGERPRINT_CB = (short)0x00cb;
protected static final short TAG_FINGERPRINT_CC = (short)0x00cc;
protected static final short TAG_KEY_GENERATION_DATES = (short)0x00cd;
protected static final short TAG_GENERATION_DATE_SIG = (short)0x00ce;
protected static final short TAG_GENERATION_DATE_DEC = (short)0x00cf;
protected static final short TAG_GENERATION_DATE_AUT = (short)0x00d0;
protected static final short TAG_RESETTING_CODE = (short)0x00d3;
protected static final short TAG_EXTENDED_LENGTH_INFORMATION = (short)0x7f66;
protected static final short TAG_PRIVATE_DO_0101 = (short)0x0101;
protected static final short TAG_PRIVATE_DO_0102 = (short)0x0102;
protected static final short TAG_PRIVATE_DO_0103 = (short)0x0103;
protected static final short TAG_PRIVATE_DO_0104 = (short)0x0104;
protected static final short TAG_AES_KEY = (short)0x00d5;
protected static final short CRT_AUTHENTICATION_KEY = (short)0xa400;
protected static final short CRT_SECURE_MESSAGING_KEY = (short)0xa600;
protected static final short CRT_SIGNATURE_KEY = (short)0xb600;
protected static final short CRT_DECRYPTION_KEY = (short)0xb800;
protected static final byte CLA_MASK_CHAINING = (byte)0x10;
protected static final byte CLA_MASK_SECURE_MESSAGING = (byte)0x04;
protected static final byte INS_SELECT_DATA = (byte)0xA5;
protected static final byte INS_GET_DATA = (byte)0xCA;
protected static final byte INS_GET_NEXT_DATA = (byte)0xCC;
protected static final byte INS_VERIFY = (byte)0x20;
protected static final byte INS_CHANGE_REFERENCE_DATA = (byte)0x24;
protected static final byte INS_RESET_RETRY_COUNTER = (byte)0x2C;
protected static final byte INS_PUT_DATA_DA = (byte)0xDA;
protected static final byte INS_PUT_DATA_DB = (byte)0xDB;
protected static final byte INS_GENERATE_ASYMMETRIC_KEY_PAIR = (byte)0x47;
protected static final byte INS_PERFORM_SECURITY_OPERATION = (byte)0x2A;
protected static final byte INS_INTERNAL_AUTHENTICATE = (byte)0x88;
protected static final byte INS_GET_RESPONSE = (byte)0xC0;
protected static final byte INS_GET_CHALLENGE = (byte)0x84;
protected static final byte INS_TERMINATE_DF = (byte)0xE6;
protected static final byte INS_ACTIVATE_FILE = (byte)0x44;
protected static final short SW_TERMINATED = (short)0x6285;
protected static final short SW_MEMORY_FAILURE = (short)0x6581;
protected static final short SW_CHAINING_ERROR = (short)0x6883;
protected static final short SW_REFERENCE_DATA_NOT_FOUND = (short)0x6A88;
protected static final byte[] HISTORICAL_BYTES = {
(byte)0x00, /* category indicator byte */
(byte)0x31, /* card service data */
(byte)0xC5, /* ... */
(byte)0x73, /* card capabilities */
(byte)0xC0, /* 1st byte: "methods supported" see ISO 7816-4 */
(byte)0x01, /* 2nd byte: "data coding byte" idem */
(byte)0x80, /* 3rd byte: command chaining (not extended length by default as all readers do not support them...) */
(byte)0x05, /* status indicator byte : operational state */
(byte)0x90, /* SW1 */
(byte)0x00 /* SW2 */
};
protected static final byte[] EXTENDED_CAPABILITIES = {
(byte)(0x80 | /* support secure messaging */
0x40 | /* support get challenge */
0x20 | /* support key import */
0x10 | /* support pw status changes */
0x08 | /* support private DOs (0101-0104) */
0x04 | /* support algorithm attributes changes */
0x02), /* support PSO:DEC AES */
(byte)0x01, /* SM 0x01 = 128 bits, 0x02 = 256 bits */
(byte)0x00, (byte)0x20, /* max length get challenge */
(byte)0x04, (byte)0x80, /* max length of carholder certificate */
(byte)0x00, (byte)0xff, /* max length of special DOs (private, login, url) */
(byte)0x00, /* PIN format 2 not supported */
(byte)0x00 /* RFU */
};
protected static final short aesKeyLength() {
return (short)(16 * EXTENDED_CAPABILITIES[1]);
}
protected static final short challengeMaxLength() {
return Util.getShort(EXTENDED_CAPABILITIES, (short)2);
}
protected static final short cardholderCertificateMaxLength() {
return Util.getShort(EXTENDED_CAPABILITIES, (short)4);
}
protected static final short specialDoMaxLength() {
return Util.getShort(EXTENDED_CAPABILITIES, (short)6);
}
protected static final byte[] DSI_SHA224_HEADER = {
(byte)0x30, (byte)0x2D,
(byte)0x30, (byte)0x0D,
(byte)0x06, (byte)0x09, (byte)0x60, (byte)0x86, (byte)0x48, (byte)0x01, (byte)0x65, (byte)0x03, (byte)0x04, (byte)0x02, (byte)0x04,
(byte)0x05, (byte)0x00,
(byte)0x04, (byte)0x1C
};
protected static final byte[] DSI_SHA256_HEADER = {
(byte)0x30, (byte)0x31,
(byte)0x30, (byte)0x0D,
(byte)0x06, (byte)0x09, (byte)0x60, (byte)0x86, (byte)0x48, (byte)0x01, (byte)0x65, (byte)0x03, (byte)0x04, (byte)0x02, (byte)0x01,
(byte)0x05, (byte)0x00,
(byte)0x04, (byte)0x20
};
protected static final byte[] DSI_SHA384_HEADER = {
(byte)0x30, (byte)0x41,
(byte)0x30, (byte)0x0D,
(byte)0x06, (byte)0x09, (byte)0x60, (byte)0x86, (byte)0x48, (byte)0x01, (byte)0x65, (byte)0x03, (byte)0x04, (byte)0x02, (byte)0x02,
(byte)0x05, (byte)0x00,
(byte)0x04, (byte)0x30
};
protected static final byte[] DSI_SHA512_HEADER = {
(byte)0x30, (byte)0x51,
(byte)0x30, (byte)0x0D,
(byte)0x06, (byte)0x09, (byte)0x60, (byte)0x86, (byte)0x48, (byte)0x01, (byte)0x65, (byte)0x03, (byte)0x04, (byte)0x02, (byte)0x03,
(byte)0x05, (byte)0x00,
(byte)0x04, (byte)0x40
};
protected static final byte ALGORITHM_ATTRIBUTES_MIN_LENGTH = 6;
protected static final byte ALGORITHM_ATTRIBUTES_MAX_LENGTH = 13;
protected static final byte[] ALGORITHM_ATTRIBUTES_DEFAULT = {
(byte)0x01, /* RSA */
(byte)0x08, (byte)0x00, /* 2048 bits modulus */
(byte)0x00, (byte)0x11, /* 65537 = 17 bits public exponent */
(byte)0x03 /* crt form with modulus */
};
protected static final byte[] ALGORITHM_ATTRIBUTES_DEFAULT_SECURE_MESSAGING = {
(byte)0x12, /* ECDH */
(byte)0x2A, (byte)0x86, (byte)0x48, (byte)0xCE, (byte)0x3D, (byte)0x03, (byte)0x01, (byte)0x07, /* ansix9p256r1 */
(byte)0xFF /* with public key */
};
protected static final byte[] RSA_EXPONENT = { (byte)0x01, (byte)0x00, (byte)0x01 };
protected static final short AES_BLOCK_SIZE = (short)16;
}

View File

@@ -0,0 +1,605 @@
/*
SmartPGP : JavaCard implementation of OpenPGP card v3 specification
https://github.com/ANSSI-FR/smartpgp
Copyright (C) 2016 ANSSI
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 fr.anssi.smartpgp;
public final class ECConstants {
protected static final byte[] ansix9p256r1_oid =
{ (byte)0x2A, (byte)0x86, (byte)0x48, (byte)0xCE, (byte)0x3D, (byte)0x03, (byte)0x01, (byte)0x07 };
protected static final byte[] ansix9p256r1_field = {
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF
};
protected static final byte[] ansix9p256r1_a = {
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFC
};
protected static final byte[] ansix9p256r1_b = {
(byte)0x5A, (byte)0xC6, (byte)0x35, (byte)0xD8,
(byte)0xAA, (byte)0x3A, (byte)0x93, (byte)0xE7,
(byte)0xB3, (byte)0xEB, (byte)0xBD, (byte)0x55,
(byte)0x76, (byte)0x98, (byte)0x86, (byte)0xBC,
(byte)0x65, (byte)0x1D, (byte)0x06, (byte)0xB0,
(byte)0xCC, (byte)0x53, (byte)0xB0, (byte)0xF6,
(byte)0x3B, (byte)0xCE, (byte)0x3C, (byte)0x3E,
(byte)0x27, (byte)0xD2, (byte)0x60, (byte)0x4B
};
protected static final byte[] ansix9p256r1_g = {
(byte)0x04,
(byte)0x6B, (byte)0x17, (byte)0xD1, (byte)0xF2,
(byte)0xE1, (byte)0x2C, (byte)0x42, (byte)0x47,
(byte)0xF8, (byte)0xBC, (byte)0xE6, (byte)0xE5,
(byte)0x63, (byte)0xA4, (byte)0x40, (byte)0xF2,
(byte)0x77, (byte)0x03, (byte)0x7D, (byte)0x81,
(byte)0x2D, (byte)0xEB, (byte)0x33, (byte)0xA0,
(byte)0xF4, (byte)0xA1, (byte)0x39, (byte)0x45,
(byte)0xD8, (byte)0x98, (byte)0xC2, (byte)0x96,
(byte)0x4F, (byte)0xE3, (byte)0x42, (byte)0xE2,
(byte)0xFE, (byte)0x1A, (byte)0x7F, (byte)0x9B,
(byte)0x8E, (byte)0xE7, (byte)0xEB, (byte)0x4A,
(byte)0x7C, (byte)0x0F, (byte)0x9E, (byte)0x16,
(byte)0x2B, (byte)0xCE, (byte)0x33, (byte)0x57,
(byte)0x6B, (byte)0x31, (byte)0x5E, (byte)0xCE,
(byte)0xCB, (byte)0xB6, (byte)0x40, (byte)0x68,
(byte)0x37, (byte)0xBF, (byte)0x51, (byte)0xF5
};
protected static final byte[] ansix9p256r1_r = {
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xBC, (byte)0xE6, (byte)0xFA, (byte)0xAD,
(byte)0xA7, (byte)0x17, (byte)0x9E, (byte)0x84,
(byte)0xF3, (byte)0xB9, (byte)0xCA, (byte)0xC2,
(byte)0xFC, (byte)0x63, (byte)0x25, (byte)0x51
};
protected static final byte[] ansix9p384r1_oid =
{ (byte)0x2B, (byte)0x81, (byte)0x04, (byte)0x00, (byte)0x22 };
protected static final byte[] ansix9p384r1_field = {
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFE,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF
};
protected static final byte[] ansix9p384r1_a = {
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFE,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFC
};
protected static final byte[] ansix9p384r1_b = {
(byte)0xB3, (byte)0x31, (byte)0x2F, (byte)0xA7,
(byte)0xE2, (byte)0x3E, (byte)0xE7, (byte)0xE4,
(byte)0x98, (byte)0x8E, (byte)0x05, (byte)0x6B,
(byte)0xE3, (byte)0xF8, (byte)0x2D, (byte)0x19,
(byte)0x18, (byte)0x1D, (byte)0x9C, (byte)0x6E,
(byte)0xFE, (byte)0x81, (byte)0x41, (byte)0x12,
(byte)0x03, (byte)0x14, (byte)0x08, (byte)0x8F,
(byte)0x50, (byte)0x13, (byte)0x87, (byte)0x5A,
(byte)0xC6, (byte)0x56, (byte)0x39, (byte)0x8D,
(byte)0x8A, (byte)0x2E, (byte)0xD1, (byte)0x9D,
(byte)0x2A, (byte)0x85, (byte)0xC8, (byte)0xED,
(byte)0xD3, (byte)0xEC, (byte)0x2A, (byte)0xEF
};
protected static final byte[] ansix9p384r1_g = {
(byte)0x04,
(byte)0xAA, (byte)0x87, (byte)0xCA, (byte)0x22,
(byte)0xBE, (byte)0x8B, (byte)0x05, (byte)0x37,
(byte)0x8E, (byte)0xB1, (byte)0xC7, (byte)0x1E,
(byte)0xF3, (byte)0x20, (byte)0xAD, (byte)0x74,
(byte)0x6E, (byte)0x1D, (byte)0x3B, (byte)0x62,
(byte)0x8B, (byte)0xA7, (byte)0x9B, (byte)0x98,
(byte)0x59, (byte)0xF7, (byte)0x41, (byte)0xE0,
(byte)0x82, (byte)0x54, (byte)0x2A, (byte)0x38,
(byte)0x55, (byte)0x02, (byte)0xF2, (byte)0x5D,
(byte)0xBF, (byte)0x55, (byte)0x29, (byte)0x6C,
(byte)0x3A, (byte)0x54, (byte)0x5E, (byte)0x38,
(byte)0x72, (byte)0x76, (byte)0x0A, (byte)0xB7,
(byte)0x36, (byte)0x17, (byte)0xDE, (byte)0x4A,
(byte)0x96, (byte)0x26, (byte)0x2C, (byte)0x6F,
(byte)0x5D, (byte)0x9E, (byte)0x98, (byte)0xBF,
(byte)0x92, (byte)0x92, (byte)0xDC, (byte)0x29,
(byte)0xF8, (byte)0xF4, (byte)0x1D, (byte)0xBD,
(byte)0x28, (byte)0x9A, (byte)0x14, (byte)0x7C,
(byte)0xE9, (byte)0xDA, (byte)0x31, (byte)0x13,
(byte)0xB5, (byte)0xF0, (byte)0xB8, (byte)0xC0,
(byte)0x0A, (byte)0x60, (byte)0xB1, (byte)0xCE,
(byte)0x1D, (byte)0x7E, (byte)0x81, (byte)0x9D,
(byte)0x7A, (byte)0x43, (byte)0x1D, (byte)0x7C,
(byte)0x90, (byte)0xEA, (byte)0x0E, (byte)0x5F
};
protected static final byte[] ansix9p384r1_r = {
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xC7, (byte)0x63, (byte)0x4D, (byte)0x81,
(byte)0xF4, (byte)0x37, (byte)0x2D, (byte)0xDF,
(byte)0x58, (byte)0x1A, (byte)0x0D, (byte)0xB2,
(byte)0x48, (byte)0xB0, (byte)0xA7, (byte)0x7A,
(byte)0xEC, (byte)0xEC, (byte)0x19, (byte)0x6A,
(byte)0xCC, (byte)0xC5, (byte)0x29, (byte)0x73
};
protected static final byte[] ansix9p521r1_oid =
{ (byte)0x2B, (byte)0x81, (byte)0x04, (byte)0x00, (byte)0x23 };
protected static final byte[] ansix9p521r1_field = {
(byte)0x01, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF
};
protected static final byte[] ansix9p521r1_a = {
(byte)0x01, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFC
};
protected static final byte[] ansix9p521r1_b = {
(byte)0x00, (byte)0x51, (byte)0x95, (byte)0x3E,
(byte)0xB9, (byte)0x61, (byte)0x8E, (byte)0x1C,
(byte)0x9A, (byte)0x1F, (byte)0x92, (byte)0x9A,
(byte)0x21, (byte)0xA0, (byte)0xB6, (byte)0x85,
(byte)0x40, (byte)0xEE, (byte)0xA2, (byte)0xDA,
(byte)0x72, (byte)0x5B, (byte)0x99, (byte)0xB3,
(byte)0x15, (byte)0xF3, (byte)0xB8, (byte)0xB4,
(byte)0x89, (byte)0x91, (byte)0x8E, (byte)0xF1,
(byte)0x09, (byte)0xE1, (byte)0x56, (byte)0x19,
(byte)0x39, (byte)0x51, (byte)0xEC, (byte)0x7E,
(byte)0x93, (byte)0x7B, (byte)0x16, (byte)0x52,
(byte)0xC0, (byte)0xBD, (byte)0x3B, (byte)0xB1,
(byte)0xBF, (byte)0x07, (byte)0x35, (byte)0x73,
(byte)0xDF, (byte)0x88, (byte)0x3D, (byte)0x2C,
(byte)0x34, (byte)0xF1, (byte)0xEF, (byte)0x45,
(byte)0x1F, (byte)0xD4, (byte)0x6B, (byte)0x50,
(byte)0x3F, (byte)0x00
};
protected static final byte[] ansix9p521r1_g = {
(byte)0x04,
(byte)0x00, (byte)0xC6, (byte)0x85, (byte)0x8E,
(byte)0x06, (byte)0xB7, (byte)0x04, (byte)0x04,
(byte)0xE9, (byte)0xCD, (byte)0x9E, (byte)0x3E,
(byte)0xCB, (byte)0x66, (byte)0x23, (byte)0x95,
(byte)0xB4, (byte)0x42, (byte)0x9C, (byte)0x64,
(byte)0x81, (byte)0x39, (byte)0x05, (byte)0x3F,
(byte)0xB5, (byte)0x21, (byte)0xF8, (byte)0x28,
(byte)0xAF, (byte)0x60, (byte)0x6B, (byte)0x4D,
(byte)0x3D, (byte)0xBA, (byte)0xA1, (byte)0x4B,
(byte)0x5E, (byte)0x77, (byte)0xEF, (byte)0xE7,
(byte)0x59, (byte)0x28, (byte)0xFE, (byte)0x1D,
(byte)0xC1, (byte)0x27, (byte)0xA2, (byte)0xFF,
(byte)0xA8, (byte)0xDE, (byte)0x33, (byte)0x48,
(byte)0xB3, (byte)0xC1, (byte)0x85, (byte)0x6A,
(byte)0x42, (byte)0x9B, (byte)0xF9, (byte)0x7E,
(byte)0x7E, (byte)0x31, (byte)0xC2, (byte)0xE5,
(byte)0xBD, (byte)0x66,
(byte)0x01, (byte)0x18, (byte)0x39, (byte)0x29,
(byte)0x6A, (byte)0x78, (byte)0x9A, (byte)0x3B,
(byte)0xC0, (byte)0x04, (byte)0x5C, (byte)0x8A,
(byte)0x5F, (byte)0xB4, (byte)0x2C, (byte)0x7D,
(byte)0x1B, (byte)0xD9, (byte)0x98, (byte)0xF5,
(byte)0x44, (byte)0x49, (byte)0x57, (byte)0x9B,
(byte)0x44, (byte)0x68, (byte)0x17, (byte)0xAF,
(byte)0xBD, (byte)0x17, (byte)0x27, (byte)0x3E,
(byte)0x66, (byte)0x2C, (byte)0x97, (byte)0xEE,
(byte)0x72, (byte)0x99, (byte)0x5E, (byte)0xF4,
(byte)0x26, (byte)0x40, (byte)0xC5, (byte)0x50,
(byte)0xB9, (byte)0x01, (byte)0x3F, (byte)0xAD,
(byte)0x07, (byte)0x61, (byte)0x35, (byte)0x3C,
(byte)0x70, (byte)0x86, (byte)0xA2, (byte)0x72,
(byte)0xC2, (byte)0x40, (byte)0x88, (byte)0xBE,
(byte)0x94, (byte)0x76, (byte)0x9F, (byte)0xD1,
(byte)0x66, (byte)0x50
};
protected static final byte[] ansix9p521r1_r = {
(byte)0x01, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF,
(byte)0xFF, (byte)0xFA, (byte)0x51, (byte)0x86,
(byte)0x87, (byte)0x83, (byte)0xBF, (byte)0x2F,
(byte)0x96, (byte)0x6B, (byte)0x7F, (byte)0xCC,
(byte)0x01, (byte)0x48, (byte)0xF7, (byte)0x09,
(byte)0xA5, (byte)0xD0, (byte)0x3B, (byte)0xB5,
(byte)0xC9, (byte)0xB8, (byte)0x89, (byte)0x9C,
(byte)0x47, (byte)0xAE, (byte)0xBB, (byte)0x6F,
(byte)0xB7, (byte)0x1E, (byte)0x91, (byte)0x38,
(byte)0x64, (byte)0x09
};
protected static final byte[] brainpoolP256r1_oid =
{ (byte)0x2B, (byte)0x24, (byte)0x03, (byte)0x03, (byte)0x02, (byte)0x08, (byte)0x01, (byte)0x01, (byte)0x07 };
protected static final byte[] brainpoolP256r1_field = {
(byte)0xA9, (byte)0xFB, (byte)0x57, (byte)0xDB,
(byte)0xA1, (byte)0xEE, (byte)0xA9, (byte)0xBC,
(byte)0x3E, (byte)0x66, (byte)0x0A, (byte)0x90,
(byte)0x9D, (byte)0x83, (byte)0x8D, (byte)0x72,
(byte)0x6E, (byte)0x3B, (byte)0xF6, (byte)0x23,
(byte)0xD5, (byte)0x26, (byte)0x20, (byte)0x28,
(byte)0x20, (byte)0x13, (byte)0x48, (byte)0x1D,
(byte)0x1F, (byte)0x6E, (byte)0x53, (byte)0x77
};
protected static final byte[] brainpoolP256r1_a = {
(byte)0x7D, (byte)0x5A, (byte)0x09, (byte)0x75,
(byte)0xFC, (byte)0x2C, (byte)0x30, (byte)0x57,
(byte)0xEE, (byte)0xF6, (byte)0x75, (byte)0x30,
(byte)0x41, (byte)0x7A, (byte)0xFF, (byte)0xE7,
(byte)0xFB, (byte)0x80, (byte)0x55, (byte)0xC1,
(byte)0x26, (byte)0xDC, (byte)0x5C, (byte)0x6C,
(byte)0xE9, (byte)0x4A, (byte)0x4B, (byte)0x44,
(byte)0xF3, (byte)0x30, (byte)0xB5, (byte)0xD9
};
protected static final byte[] brainpoolP256r1_b = {
(byte)0x26, (byte)0xDC, (byte)0x5C, (byte)0x6C,
(byte)0xE9, (byte)0x4A, (byte)0x4B, (byte)0x44,
(byte)0xF3, (byte)0x30, (byte)0xB5, (byte)0xD9,
(byte)0xBB, (byte)0xD7, (byte)0x7C, (byte)0xBF,
(byte)0x95, (byte)0x84, (byte)0x16, (byte)0x29,
(byte)0x5C, (byte)0xF7, (byte)0xE1, (byte)0xCE,
(byte)0x6B, (byte)0xCC, (byte)0xDC, (byte)0x18,
(byte)0xFF, (byte)0x8C, (byte)0x07, (byte)0xB6
};
protected static final byte[] brainpoolP256r1_g = {
(byte)0x04,
(byte)0x8B, (byte)0xD2, (byte)0xAE, (byte)0xB9,
(byte)0xCB, (byte)0x7E, (byte)0x57, (byte)0xCB,
(byte)0x2C, (byte)0x4B, (byte)0x48, (byte)0x2F,
(byte)0xFC, (byte)0x81, (byte)0xB7, (byte)0xAF,
(byte)0xB9, (byte)0xDE, (byte)0x27, (byte)0xE1,
(byte)0xE3, (byte)0xBD, (byte)0x23, (byte)0xC2,
(byte)0x3A, (byte)0x44, (byte)0x53, (byte)0xBD,
(byte)0x9A, (byte)0xCE, (byte)0x32, (byte)0x62,
(byte)0x54, (byte)0x7E, (byte)0xF8, (byte)0x35,
(byte)0xC3, (byte)0xDA, (byte)0xC4, (byte)0xFD,
(byte)0x97, (byte)0xF8, (byte)0x46, (byte)0x1A,
(byte)0x14, (byte)0x61, (byte)0x1D, (byte)0xC9,
(byte)0xC2, (byte)0x77, (byte)0x45, (byte)0x13,
(byte)0x2D, (byte)0xED, (byte)0x8E, (byte)0x54,
(byte)0x5C, (byte)0x1D, (byte)0x54, (byte)0xC7,
(byte)0x2F, (byte)0x04, (byte)0x69, (byte)0x97
};
protected static final byte[] brainpoolP256r1_r = {
(byte)0xA9, (byte)0xFB, (byte)0x57, (byte)0xDB,
(byte)0xA1, (byte)0xEE, (byte)0xA9, (byte)0xBC,
(byte)0x3E, (byte)0x66, (byte)0x0A, (byte)0x90,
(byte)0x9D, (byte)0x83, (byte)0x8D, (byte)0x71,
(byte)0x8C, (byte)0x39, (byte)0x7A, (byte)0xA3,
(byte)0xB5, (byte)0x61, (byte)0xA6, (byte)0xF7,
(byte)0x90, (byte)0x1E, (byte)0x0E, (byte)0x82,
(byte)0x97, (byte)0x48, (byte)0x56, (byte)0xA7
};
protected static final byte[] brainpoolP384r1_oid =
{ (byte)0x2B, (byte)0x24, (byte)0x03, (byte)0x03, (byte)0x02, (byte)0x08, (byte)0x01, (byte)0x01, (byte)0x0B };
protected static final byte[] brainpoolP384r1_field = {
(byte)0x8C, (byte)0xB9, (byte)0x1E, (byte)0x82,
(byte)0xA3, (byte)0x38, (byte)0x6D, (byte)0x28,
(byte)0x0F, (byte)0x5D, (byte)0x6F, (byte)0x7E,
(byte)0x50, (byte)0xE6, (byte)0x41, (byte)0xDF,
(byte)0x15, (byte)0x2F, (byte)0x71, (byte)0x09,
(byte)0xED, (byte)0x54, (byte)0x56, (byte)0xB4,
(byte)0x12, (byte)0xB1, (byte)0xDA, (byte)0x19,
(byte)0x7F, (byte)0xB7, (byte)0x11, (byte)0x23,
(byte)0xAC, (byte)0xD3, (byte)0xA7, (byte)0x29,
(byte)0x90, (byte)0x1D, (byte)0x1A, (byte)0x71,
(byte)0x87, (byte)0x47, (byte)0x00, (byte)0x13,
(byte)0x31, (byte)0x07, (byte)0xEC, (byte)0x53
};
protected static final byte[] brainpoolP384r1_a = {
(byte)0x7B, (byte)0xC3, (byte)0x82, (byte)0xC6,
(byte)0x3D, (byte)0x8C, (byte)0x15, (byte)0x0C,
(byte)0x3C, (byte)0x72, (byte)0x08, (byte)0x0A,
(byte)0xCE, (byte)0x05, (byte)0xAF, (byte)0xA0,
(byte)0xC2, (byte)0xBE, (byte)0xA2, (byte)0x8E,
(byte)0x4F, (byte)0xB2, (byte)0x27, (byte)0x87,
(byte)0x13, (byte)0x91, (byte)0x65, (byte)0xEF,
(byte)0xBA, (byte)0x91, (byte)0xF9, (byte)0x0F,
(byte)0x8A, (byte)0xA5, (byte)0x81, (byte)0x4A,
(byte)0x50, (byte)0x3A, (byte)0xD4, (byte)0xEB,
(byte)0x04, (byte)0xA8, (byte)0xC7, (byte)0xDD,
(byte)0x22, (byte)0xCE, (byte)0x28, (byte)0x26
};
protected static final byte[] brainpoolP384r1_b = {
(byte)0x04, (byte)0xA8, (byte)0xC7, (byte)0xDD,
(byte)0x22, (byte)0xCE, (byte)0x28, (byte)0x26,
(byte)0x8B, (byte)0x39, (byte)0xB5, (byte)0x54,
(byte)0x16, (byte)0xF0, (byte)0x44, (byte)0x7C,
(byte)0x2F, (byte)0xB7, (byte)0x7D, (byte)0xE1,
(byte)0x07, (byte)0xDC, (byte)0xD2, (byte)0xA6,
(byte)0x2E, (byte)0x88, (byte)0x0E, (byte)0xA5,
(byte)0x3E, (byte)0xEB, (byte)0x62, (byte)0xD5,
(byte)0x7C, (byte)0xB4, (byte)0x39, (byte)0x02,
(byte)0x95, (byte)0xDB, (byte)0xC9, (byte)0x94,
(byte)0x3A, (byte)0xB7, (byte)0x86, (byte)0x96,
(byte)0xFA, (byte)0x50, (byte)0x4C, (byte)0x11
};
protected static final byte[] brainpoolP384r1_g = {
(byte)0x04,
(byte)0x1D, (byte)0x1C, (byte)0x64, (byte)0xF0,
(byte)0x68, (byte)0xCF, (byte)0x45, (byte)0xFF,
(byte)0xA2, (byte)0xA6, (byte)0x3A, (byte)0x81,
(byte)0xB7, (byte)0xC1, (byte)0x3F, (byte)0x6B,
(byte)0x88, (byte)0x47, (byte)0xA3, (byte)0xE7,
(byte)0x7E, (byte)0xF1, (byte)0x4F, (byte)0xE3,
(byte)0xDB, (byte)0x7F, (byte)0xCA, (byte)0xFE,
(byte)0x0C, (byte)0xBD, (byte)0x10, (byte)0xE8,
(byte)0xE8, (byte)0x26, (byte)0xE0, (byte)0x34,
(byte)0x36, (byte)0xD6, (byte)0x46, (byte)0xAA,
(byte)0xEF, (byte)0x87, (byte)0xB2, (byte)0xE2,
(byte)0x47, (byte)0xD4, (byte)0xAF, (byte)0x1E,
(byte)0x8A, (byte)0xBE, (byte)0x1D, (byte)0x75,
(byte)0x20, (byte)0xF9, (byte)0xC2, (byte)0xA4,
(byte)0x5C, (byte)0xB1, (byte)0xEB, (byte)0x8E,
(byte)0x95, (byte)0xCF, (byte)0xD5, (byte)0x52,
(byte)0x62, (byte)0xB7, (byte)0x0B, (byte)0x29,
(byte)0xFE, (byte)0xEC, (byte)0x58, (byte)0x64,
(byte)0xE1, (byte)0x9C, (byte)0x05, (byte)0x4F,
(byte)0xF9, (byte)0x91, (byte)0x29, (byte)0x28,
(byte)0x0E, (byte)0x46, (byte)0x46, (byte)0x21,
(byte)0x77, (byte)0x91, (byte)0x81, (byte)0x11,
(byte)0x42, (byte)0x82, (byte)0x03, (byte)0x41,
(byte)0x26, (byte)0x3C, (byte)0x53, (byte)0x15
};
protected static final byte[] brainpoolP384r1_r = {
(byte)0x8C, (byte)0xB9, (byte)0x1E, (byte)0x82,
(byte)0xA3, (byte)0x38, (byte)0x6D, (byte)0x28,
(byte)0x0F, (byte)0x5D, (byte)0x6F, (byte)0x7E,
(byte)0x50, (byte)0xE6, (byte)0x41, (byte)0xDF,
(byte)0x15, (byte)0x2F, (byte)0x71, (byte)0x09,
(byte)0xED, (byte)0x54, (byte)0x56, (byte)0xB3,
(byte)0x1F, (byte)0x16, (byte)0x6E, (byte)0x6C,
(byte)0xAC, (byte)0x04, (byte)0x25, (byte)0xA7,
(byte)0xCF, (byte)0x3A, (byte)0xB6, (byte)0xAF,
(byte)0x6B, (byte)0x7F, (byte)0xC3, (byte)0x10,
(byte)0x3B, (byte)0x88, (byte)0x32, (byte)0x02,
(byte)0xE9, (byte)0x04, (byte)0x65, (byte)0x65
};
protected static final byte[] brainpoolP512r1_oid =
{ (byte)0x2B, (byte)0x24, (byte)0x03, (byte)0x03, (byte)0x02, (byte)0x08, (byte)0x01, (byte)0x01, (byte)0x0D };
protected static final byte[] brainpoolP512r1_field = {
(byte)0xAA, (byte)0xDD, (byte)0x9D, (byte)0xB8,
(byte)0xDB, (byte)0xE9, (byte)0xC4, (byte)0x8B,
(byte)0x3F, (byte)0xD4, (byte)0xE6, (byte)0xAE,
(byte)0x33, (byte)0xC9, (byte)0xFC, (byte)0x07,
(byte)0xCB, (byte)0x30, (byte)0x8D, (byte)0xB3,
(byte)0xB3, (byte)0xC9, (byte)0xD2, (byte)0x0E,
(byte)0xD6, (byte)0x63, (byte)0x9C, (byte)0xCA,
(byte)0x70, (byte)0x33, (byte)0x08, (byte)0x71,
(byte)0x7D, (byte)0x4D, (byte)0x9B, (byte)0x00,
(byte)0x9B, (byte)0xC6, (byte)0x68, (byte)0x42,
(byte)0xAE, (byte)0xCD, (byte)0xA1, (byte)0x2A,
(byte)0xE6, (byte)0xA3, (byte)0x80, (byte)0xE6,
(byte)0x28, (byte)0x81, (byte)0xFF, (byte)0x2F,
(byte)0x2D, (byte)0x82, (byte)0xC6, (byte)0x85,
(byte)0x28, (byte)0xAA, (byte)0x60, (byte)0x56,
(byte)0x58, (byte)0x3A, (byte)0x48, (byte)0xF3
};
protected static final byte[] brainpoolP512r1_a = {
(byte)0x78, (byte)0x30, (byte)0xA3, (byte)0x31,
(byte)0x8B, (byte)0x60, (byte)0x3B, (byte)0x89,
(byte)0xE2, (byte)0x32, (byte)0x71, (byte)0x45,
(byte)0xAC, (byte)0x23, (byte)0x4C, (byte)0xC5,
(byte)0x94, (byte)0xCB, (byte)0xDD, (byte)0x8D,
(byte)0x3D, (byte)0xF9, (byte)0x16, (byte)0x10,
(byte)0xA8, (byte)0x34, (byte)0x41, (byte)0xCA,
(byte)0xEA, (byte)0x98, (byte)0x63, (byte)0xBC,
(byte)0x2D, (byte)0xED, (byte)0x5D, (byte)0x5A,
(byte)0xA8, (byte)0x25, (byte)0x3A, (byte)0xA1,
(byte)0x0A, (byte)0x2E, (byte)0xF1, (byte)0xC9,
(byte)0x8B, (byte)0x9A, (byte)0xC8, (byte)0xB5,
(byte)0x7F, (byte)0x11, (byte)0x17, (byte)0xA7,
(byte)0x2B, (byte)0xF2, (byte)0xC7, (byte)0xB9,
(byte)0xE7, (byte)0xC1, (byte)0xAC, (byte)0x4D,
(byte)0x77, (byte)0xFC, (byte)0x94, (byte)0xCA
};
protected static final byte[] brainpoolP512r1_b = {
(byte)0x3D, (byte)0xF9, (byte)0x16, (byte)0x10,
(byte)0xA8, (byte)0x34, (byte)0x41, (byte)0xCA,
(byte)0xEA, (byte)0x98, (byte)0x63, (byte)0xBC,
(byte)0x2D, (byte)0xED, (byte)0x5D, (byte)0x5A,
(byte)0xA8, (byte)0x25, (byte)0x3A, (byte)0xA1,
(byte)0x0A, (byte)0x2E, (byte)0xF1, (byte)0xC9,
(byte)0x8B, (byte)0x9A, (byte)0xC8, (byte)0xB5,
(byte)0x7F, (byte)0x11, (byte)0x17, (byte)0xA7,
(byte)0x2B, (byte)0xF2, (byte)0xC7, (byte)0xB9,
(byte)0xE7, (byte)0xC1, (byte)0xAC, (byte)0x4D,
(byte)0x77, (byte)0xFC, (byte)0x94, (byte)0xCA,
(byte)0xDC, (byte)0x08, (byte)0x3E, (byte)0x67,
(byte)0x98, (byte)0x40, (byte)0x50, (byte)0xB7,
(byte)0x5E, (byte)0xBA, (byte)0xE5, (byte)0xDD,
(byte)0x28, (byte)0x09, (byte)0xBD, (byte)0x63,
(byte)0x80, (byte)0x16, (byte)0xF7, (byte)0x23
};
protected static final byte[] brainpoolP512r1_g = {
(byte)0x04,
(byte)0x81, (byte)0xAE, (byte)0xE4, (byte)0xBD,
(byte)0xD8, (byte)0x2E, (byte)0xD9, (byte)0x64,
(byte)0x5A, (byte)0x21, (byte)0x32, (byte)0x2E,
(byte)0x9C, (byte)0x4C, (byte)0x6A, (byte)0x93,
(byte)0x85, (byte)0xED, (byte)0x9F, (byte)0x70,
(byte)0xB5, (byte)0xD9, (byte)0x16, (byte)0xC1,
(byte)0xB4, (byte)0x3B, (byte)0x62, (byte)0xEE,
(byte)0xF4, (byte)0xD0, (byte)0x09, (byte)0x8E,
(byte)0xFF, (byte)0x3B, (byte)0x1F, (byte)0x78,
(byte)0xE2, (byte)0xD0, (byte)0xD4, (byte)0x8D,
(byte)0x50, (byte)0xD1, (byte)0x68, (byte)0x7B,
(byte)0x93, (byte)0xB9, (byte)0x7D, (byte)0x5F,
(byte)0x7C, (byte)0x6D, (byte)0x50, (byte)0x47,
(byte)0x40, (byte)0x6A, (byte)0x5E, (byte)0x68,
(byte)0x8B, (byte)0x35, (byte)0x22, (byte)0x09,
(byte)0xBC, (byte)0xB9, (byte)0xF8, (byte)0x22,
(byte)0x7D, (byte)0xDE, (byte)0x38, (byte)0x5D,
(byte)0x56, (byte)0x63, (byte)0x32, (byte)0xEC,
(byte)0xC0, (byte)0xEA, (byte)0xBF, (byte)0xA9,
(byte)0xCF, (byte)0x78, (byte)0x22, (byte)0xFD,
(byte)0xF2, (byte)0x09, (byte)0xF7, (byte)0x00,
(byte)0x24, (byte)0xA5, (byte)0x7B, (byte)0x1A,
(byte)0xA0, (byte)0x00, (byte)0xC5, (byte)0x5B,
(byte)0x88, (byte)0x1F, (byte)0x81, (byte)0x11,
(byte)0xB2, (byte)0xDC, (byte)0xDE, (byte)0x49,
(byte)0x4A, (byte)0x5F, (byte)0x48, (byte)0x5E,
(byte)0x5B, (byte)0xCA, (byte)0x4B, (byte)0xD8,
(byte)0x8A, (byte)0x27, (byte)0x63, (byte)0xAE,
(byte)0xD1, (byte)0xCA, (byte)0x2B, (byte)0x2F,
(byte)0xA8, (byte)0xF0, (byte)0x54, (byte)0x06,
(byte)0x78, (byte)0xCD, (byte)0x1E, (byte)0x0F,
(byte)0x3A, (byte)0xD8, (byte)0x08, (byte)0x92
};
protected static final byte[] brainpoolP512r1_r = {
(byte)0xAA, (byte)0xDD, (byte)0x9D, (byte)0xB8,
(byte)0xDB, (byte)0xE9, (byte)0xC4, (byte)0x8B,
(byte)0x3F, (byte)0xD4, (byte)0xE6, (byte)0xAE,
(byte)0x33, (byte)0xC9, (byte)0xFC, (byte)0x07,
(byte)0xCB, (byte)0x30, (byte)0x8D, (byte)0xB3,
(byte)0xB3, (byte)0xC9, (byte)0xD2, (byte)0x0E,
(byte)0xD6, (byte)0x63, (byte)0x9C, (byte)0xCA,
(byte)0x70, (byte)0x33, (byte)0x08, (byte)0x70,
(byte)0x55, (byte)0x3E, (byte)0x5C, (byte)0x41,
(byte)0x4C, (byte)0xA9, (byte)0x26, (byte)0x19,
(byte)0x41, (byte)0x86, (byte)0x61, (byte)0x19,
(byte)0x7F, (byte)0xAC, (byte)0x10, (byte)0x47,
(byte)0x1D, (byte)0xB1, (byte)0xD3, (byte)0x81,
(byte)0x08, (byte)0x5D, (byte)0xDA, (byte)0xDD,
(byte)0xB5, (byte)0x87, (byte)0x96, (byte)0x82,
(byte)0x9C, (byte)0xA9, (byte)0x00, (byte)0x69
};
}

View File

@@ -0,0 +1,116 @@
/*
SmartPGP : JavaCard implementation of OpenPGP card v3 specification
https://github.com/ANSSI-FR/smartpgp
Copyright (C) 2016 ANSSI
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 fr.anssi.smartpgp;
import javacard.framework.*;
import javacard.security.*;
import javacardx.apdu.*;
import javacardx.crypto.*;
public final class ECCurves {
protected final ECParams[] curves;
protected ECCurves() {
final ECParams ansix9p256r1 =
new ECParams((short)256,
ECConstants.ansix9p256r1_oid,
ECConstants.ansix9p256r1_field,
ECConstants.ansix9p256r1_a,
ECConstants.ansix9p256r1_b,
ECConstants.ansix9p256r1_g,
ECConstants.ansix9p256r1_r,
(short)1);
final ECParams ansix9p384r1 =
new ECParams((short)384,
ECConstants.ansix9p384r1_oid,
ECConstants.ansix9p384r1_field,
ECConstants.ansix9p384r1_a,
ECConstants.ansix9p384r1_b,
ECConstants.ansix9p384r1_g,
ECConstants.ansix9p384r1_r,
(short)1);
final ECParams ansix9p521r1 =
new ECParams((short)521,
ECConstants.ansix9p521r1_oid,
ECConstants.ansix9p521r1_field,
ECConstants.ansix9p521r1_a,
ECConstants.ansix9p521r1_b,
ECConstants.ansix9p521r1_g,
ECConstants.ansix9p521r1_r,
(short)1);
final ECParams brainpoolP256r1 =
new ECParams((short)256,
ECConstants.brainpoolP256r1_oid,
ECConstants.brainpoolP256r1_field,
ECConstants.brainpoolP256r1_a,
ECConstants.brainpoolP256r1_b,
ECConstants.brainpoolP256r1_g,
ECConstants.brainpoolP256r1_r,
(short)1);
final ECParams brainpoolP384r1 =
new ECParams((short)384,
ECConstants.brainpoolP384r1_oid,
ECConstants.brainpoolP384r1_field,
ECConstants.brainpoolP384r1_a,
ECConstants.brainpoolP384r1_b,
ECConstants.brainpoolP384r1_g,
ECConstants.brainpoolP384r1_r,
(short)1);
final ECParams brainpoolP512r1 =
new ECParams((short)512,
ECConstants.brainpoolP512r1_oid,
ECConstants.brainpoolP512r1_field,
ECConstants.brainpoolP512r1_a,
ECConstants.brainpoolP512r1_b,
ECConstants.brainpoolP512r1_g,
ECConstants.brainpoolP512r1_r,
(short)1);
curves = new ECParams[]{
ansix9p256r1,
ansix9p384r1,
ansix9p521r1,
brainpoolP256r1,
brainpoolP384r1,
brainpoolP512r1
};
}
protected final ECParams findByOid(final byte[] buf,
final short off,
final byte len) {
byte i = 0;
while(i < curves.length) {
if(curves[i].matchOid(buf, off, len)) {
return curves[i];
}
++i;
}
return null;
}
}

View File

@@ -0,0 +1,67 @@
/*
SmartPGP : JavaCard implementation of OpenPGP card v3 specification
https://github.com/ANSSI-FR/smartpgp
Copyright (C) 2016 ANSSI
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 fr.anssi.smartpgp;
import javacard.framework.*;
import javacard.security.*;
import javacardx.apdu.*;
import javacardx.crypto.*;
public final class ECParams {
protected final short nb_bits;
protected final byte[] oid;
protected final byte[] field, a, b, g, r;
protected final short k;
protected ECParams(final short nb_bits,
final byte[] oid,
final byte[] field, /* p */
final byte[] a,
final byte[] b,
final byte[] g,
final byte[] r, /* n */
final short k) /* h */ {
this.nb_bits = nb_bits;
this.oid = oid;
this.field = field;
this.a = a;
this.b = b;
this.g = g;
this.r = r;
this.k = k;
}
protected final boolean matchOid(final byte[] buf, final short off, final short len) {
return (len == (short)oid.length) && (Util.arrayCompare(buf, off, oid, (short)0, len) == 0);
}
protected final void setParams(final ECKey key) {
key.setFieldFP(field, (short)0, (short)field.length);
key.setA(a, (short)0, (short)a.length);
key.setB(b, (short)0, (short)b.length);
key.setG(g, (short)0, (short)g.length);
key.setR(r, (short)0, (short)r.length);
key.setK(k);
}
}

View File

@@ -0,0 +1,50 @@
/*
SmartPGP : JavaCard implementation of OpenPGP card v3 specification
https://github.com/ANSSI-FR/smartpgp
Copyright (C) 2016 ANSSI
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 fr.anssi.smartpgp;
import javacard.framework.*;
import javacard.security.*;
import javacardx.apdu.*;
import javacardx.crypto.*;
public final class Fingerprint {
protected final byte[] data;
protected Fingerprint() {
data = new byte[Constants.FINGERPRINT_SIZE];
}
protected final void reset() {
Util.arrayFillNonAtomic(data, (short)0, Constants.FINGERPRINT_SIZE, (byte)0);
}
protected final void set(final byte[] buf, final short off, final short len) {
if(len != Constants.FINGERPRINT_SIZE) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return;
}
Util.arrayCopy(buf, off, data, (short)0, len);
}
protected final short write(final byte[] buf, final short off) {
return Util.arrayCopyNonAtomic(data, (short)0, buf, off, Constants.FINGERPRINT_SIZE);
}
}

View File

@@ -0,0 +1,848 @@
/*
SmartPGP : JavaCard implementation of OpenPGP card v3 specification
https://github.com/ANSSI-FR/smartpgp
Copyright (C) 2016 ANSSI
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 fr.anssi.smartpgp;
import javacard.framework.*;
import javacard.security.*;
import javacardx.apdu.*;
import javacardx.crypto.*;
public final class PGPKey {
protected final Fingerprint fingerprint;
protected final byte[] generation_date;
protected final byte[] certificate;
protected short certificate_length;
protected final byte[] attributes;
protected byte attributes_length;
protected final boolean is_secure_messaging_key;
private KeyPair keys;
protected PGPKey(final boolean for_secure_messaging) {
is_secure_messaging_key = for_secure_messaging;
if(is_secure_messaging_key) {
fingerprint = null;
generation_date = null;
} else {
fingerprint = new Fingerprint();
generation_date = new byte[Constants.GENERATION_DATE_SIZE];
}
certificate = new byte[Constants.cardholderCertificateMaxLength()];
certificate_length = 0;
attributes = new byte[Constants.ALGORITHM_ATTRIBUTES_MAX_LENGTH];
attributes_length = 0;
reset();
}
private final void resetKeys() {
if(keys != null) {
keys.getPrivate().clearKey();
keys.getPublic().clearKey();
keys = null;
}
if(certificate_length > 0) {
certificate_length = (short)0;
Util.arrayFillNonAtomic(certificate, (short)0, certificate_length, (byte)0);
}
if(!is_secure_messaging_key) {
fingerprint.reset();
Util.arrayFillNonAtomic(generation_date, (short)0, Constants.GENERATION_DATE_SIZE, (byte)0);
}
}
protected final void reset() {
resetKeys();
JCSystem.beginTransaction();
if(attributes_length > 0) {
Util.arrayFillNonAtomic(attributes, (short)0, attributes_length, (byte)0);
attributes_length = (byte)0;
}
if(is_secure_messaging_key) {
Util.arrayCopyNonAtomic(Constants.ALGORITHM_ATTRIBUTES_DEFAULT_SECURE_MESSAGING, (short)0,
attributes, (short)0,
(short)Constants.ALGORITHM_ATTRIBUTES_DEFAULT_SECURE_MESSAGING.length);
attributes_length = (byte)Constants.ALGORITHM_ATTRIBUTES_DEFAULT_SECURE_MESSAGING.length;
} else {
Util.arrayCopyNonAtomic(Constants.ALGORITHM_ATTRIBUTES_DEFAULT, (short)0,
attributes, (short)0,
(short)Constants.ALGORITHM_ATTRIBUTES_DEFAULT.length);
attributes_length = (byte)Constants.ALGORITHM_ATTRIBUTES_DEFAULT.length;
}
JCSystem.commitTransaction();
}
protected final boolean isInitialized() {
return (keys != null) && keys.getPrivate().isInitialized() && keys.getPublic().isInitialized();
}
protected final void setCertificate(final byte[] buf, final short off, final short len) {
if((len < 0) ||
(len > Constants.cardholderCertificateMaxLength())) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
return;
}
JCSystem.beginTransaction();
if(certificate_length > 0) {
Util.arrayFillNonAtomic(certificate, (short)0, certificate_length, (byte)0);
}
Util.arrayCopyNonAtomic(buf, off, certificate, (short)0, len);
certificate_length = len;
JCSystem.commitTransaction();
}
protected final void setGenerationDate(final byte[] buf, final short off, final short len) {
if(len != Constants.GENERATION_DATE_SIZE) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
return;
}
Util.arrayCopy(buf, off, generation_date, (short)0, len);
}
protected final void setAttributes(final ECCurves ec,
final byte[] buf, final short off, final short len) {
if((len < Constants.ALGORITHM_ATTRIBUTES_MIN_LENGTH) ||
(len > Constants.ALGORITHM_ATTRIBUTES_MAX_LENGTH)) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
return;
}
switch(buf[0]) {
case 0x01:
if((len != 6) || is_secure_messaging_key) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return;
}
if((Util.getShort(buf, (short)1) < 2048) ||
(Util.getShort(buf, (short)3) != 0x11) ||
(buf[5] < 0) || (buf[5] > 3)) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return;
}
break;
case 0x12:
case 0x13:
if(len < 2) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return;
}
final byte delta = (buf[(short)(len - 1)] == (byte)0xff) ? (byte)1 : (byte)0;
final ECParams params = ec.findByOid(buf, (short)(off + 1), (byte)(len - 1 - delta));
if(params == null) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return;
}
if(is_secure_messaging_key) {
if((buf[0] != 0x12) ||
(((short)(Constants.aesKeyLength()* 8) > (short)128) &&
(params.nb_bits < 512))) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return;
}
}
break;
default:
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return;
}
resetKeys();
JCSystem.beginTransaction();
if(attributes_length > 0) {
Util.arrayFillNonAtomic(attributes, (short)0, attributes_length, (byte)0);
}
Util.arrayCopyNonAtomic(buf, off, attributes, (short)0, len);
attributes_length = (byte)len;
JCSystem.commitTransaction();
}
protected final boolean isRsa() {
return (attributes[0] == 1);
}
protected final short rsaModulusBitSize() {
return Util.getShort(attributes, (short)1);
}
protected final short rsaExponentBitSize() {
return Util.getShort(attributes, (short)3);
}
protected final boolean isEc() {
return ((attributes[0] == (byte)0x12) ||
(attributes[0] == (byte)0x13));
}
protected final ECParams ecParams(final ECCurves ec) {
final byte delta = (attributes[(short)(attributes_length - 1)] == (byte)0xff) ? (byte)1 : (byte)0;
return ec.findByOid(attributes, (short)1, (byte)(attributes_length - 1 - delta));
}
private final KeyPair generateRSA() {
final PrivateKey priv = (PrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_CRT_PRIVATE, rsaModulusBitSize(), false);
final RSAPublicKey pub = (RSAPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, rsaModulusBitSize(), false);
if((priv == null) || (pub == null)) {
return null;
}
pub.setExponent(Constants.RSA_EXPONENT, (short)0, (byte)Constants.RSA_EXPONENT.length);
return new KeyPair(pub, priv);
}
private final KeyPair generateEC(final ECCurves ec) {
final ECParams params = ecParams(ec);
final ECPrivateKey priv = (ECPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, params.nb_bits, false);
final ECPublicKey pub = (ECPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC, params.nb_bits, false);
if((priv == null) || (pub == null)) {
return null;
}
params.setParams(priv);
params.setParams(pub);
return new KeyPair(pub, priv);
}
protected final void generate(final ECCurves ec) {
KeyPair nkeys = null;
if(isRsa()) {
nkeys = generateRSA();
} else if(isEc()) {
nkeys = generateEC(ec);
}
if(nkeys == null) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return;
}
nkeys.genKeyPair();
if(!nkeys.getPublic().isInitialized() || !nkeys.getPrivate().isInitialized()) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return;
}
resetKeys();
keys = nkeys;
}
private final KeyPair importRSAKey(final byte[] buf,
final short boff, final short len,
final byte tag_count, final byte[] tag_val, final short[] tag_len) {
final short attr_modulus_bit_size = rsaModulusBitSize();
final short attr_modulus_byte_size = Common.bitsToBytes(attr_modulus_bit_size);
final RSAPrivateCrtKey priv = (RSAPrivateCrtKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_CRT_PRIVATE, attr_modulus_bit_size, false);
final RSAPublicKey pub = (RSAPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, attr_modulus_bit_size, false);
if((priv == null) || (pub == null)) {
return null;
}
short off = boff;
byte i = 0;
while(i < tag_count) {
if((short)((short)(off - boff) + tag_len[i]) > len) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return null;
}
switch(tag_val[i]) {
case (byte)0x91:
if(tag_len[i] != Common.bitsToBytes(rsaExponentBitSize())) {
return null;
}
pub.setExponent(buf, off, tag_len[i]);
break;
case (byte)0x92:
if(tag_len[i] != (short)(attr_modulus_byte_size / 2)) {
return null;
}
priv.setP(buf, off, tag_len[i]);
break;
case (byte)0x93:
if(tag_len[i] != (short)(attr_modulus_byte_size / 2)) {
return null;
}
priv.setQ(buf, off, tag_len[i]);
break;
case (byte)0x94:
if(tag_len[i] != (short)(attr_modulus_byte_size / 2)) {
return null;
}
priv.setPQ(buf, off, tag_len[i]);
break;
case (byte)0x95:
if(tag_len[i] != (short)(attr_modulus_byte_size / 2)) {
return null;
}
priv.setDP1(buf, off, tag_len[i]);
break;
case (byte)0x96:
if(tag_len[i] != (short)(attr_modulus_byte_size / 2)) {
return null;
}
priv.setDQ1(buf, off, tag_len[i]);
break;
case (byte)0x97:
if(tag_len[i] != attr_modulus_byte_size) {
return null;
}
pub.setModulus(buf, off, tag_len[i]);
break;
default:
return null;
}
off += tag_len[i];
++i;
}
if(!priv.isInitialized() || !pub.isInitialized()) {
return null;
}
return new KeyPair(pub, priv);
}
private final KeyPair importECKey(final ECCurves ec,
final byte[] buf,
final short boff, final short len,
final byte tag_count, final byte[] tag_val, final short[] tag_len) {
final ECParams params = ecParams(ec);
final ECPrivateKey priv = (ECPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE,
params.nb_bits,
false);
final ECPublicKey pub = (ECPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC,
params.nb_bits,
false);
if((priv == null) || (pub == null)) {
return null;
}
params.setParams(priv);
params.setParams(pub);
short off = boff;
byte i = 0;
while(i < tag_count) {
if((short)((short)(off - boff) + tag_len[i]) > len) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return null;
}
switch(tag_val[i]) {
case (byte)0x92:
if(tag_len[i] > Common.bitsToBytes(params.nb_bits)) {
return null;
}
priv.setS(buf, off, tag_len[i]);
break;
case (byte)0x99:
if(tag_len[i] > (short)(2 * Common.bitsToBytes(params.nb_bits) + 1)) {
return null;
}
if(((byte)(tag_len[i] - 1) & (byte)0x1) != 0) {
return null;
}
pub.setW(buf, off, tag_len[i]);
break;
default:
return null;
}
off += tag_len[i];
++i;
}
if(!priv.isInitialized() || !pub.isInitialized()) {
return null;
}
return new KeyPair(pub, priv);
}
protected final void importKey(final ECCurves ec,
final byte[] buf, final short boff, final short len) {
short off = boff;
short template_len = 0;
short template_off = 0;
short data_len = 0;
short data_off = 0;
byte data_tag_count = 0;
byte[] data_tag_val = new byte[7];
short[] data_tag_len = new short[7];
while((short)(len - (short)(off - boff)) > 2) {
switch(Util.getShort(buf, off)) {
case (short)0x7f48:
off += 2;
template_len = Common.readLength(buf, off, (short)(len - (short)(off - boff)));
off = Common.skipLength(buf, off, (short)(len - (short)(off - boff)));
template_off = off;
if(template_len > (short)(len - ((short)off - boff))) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return;
}
while((short)(template_len - (short)(off - template_off)) > 1) {
if((buf[off] < (byte)0x91) ||
(buf[off] > (byte)0x99)) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return;
}
if(data_tag_count >= data_tag_val.length) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return;
}
data_tag_val[data_tag_count] = buf[off];
++off;
data_tag_len[data_tag_count] = Common.readLength(buf, off, (short)(template_len - (short)(off - template_off)));
off = Common.skipLength(buf, off, (short)(template_len - (short)(off - template_off)));
++data_tag_count;
}
break;
case (short)0x5f48:
off += 2;
data_len = Common.readLength(buf, off, (short)(len - (short)(off - boff)));
off = Common.skipLength(buf, off, (short)(len - (short)(off - boff)));
data_off = off;
if(data_len > (short)(len - ((short)off - boff))) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return;
}
off += data_len;
break;
default:
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return;
}
}
KeyPair nkeys = null;
if(isRsa()) {
nkeys = importRSAKey(buf, data_off, data_len, data_tag_count, data_tag_val, data_tag_len);
} else if(isEc()) {
nkeys = importECKey(ec, buf, data_off, data_len, data_tag_count, data_tag_val, data_tag_len);
}
if(nkeys == null) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return;
}
if(!nkeys.getPrivate().isInitialized() || !nkeys.getPublic().isInitialized()) {
return;
}
resetKeys();
keys = nkeys;
}
protected final short writePublicKeyDo(final byte[] buf, short off) {
if(!isInitialized()) {
ISOException.throwIt(Constants.SW_REFERENCE_DATA_NOT_FOUND);
return 0;
}
final PublicKey pub = keys.getPublic();
off = Util.setShort(buf, off, (short)0x7f49);
if(isRsa()) {
final RSAPublicKey rsapub = (RSAPublicKey)pub;
final short modulus_size = Common.bitsToBytes(rsaModulusBitSize());
final short exponent_size = Common.bitsToBytes(rsaExponentBitSize());
final short mlensize = (short)((modulus_size > (short)0xff) ? 3 : 2);
final short flen =
(short)(1 + mlensize + modulus_size +
1 + 1 + exponent_size);
off = Common.writeLength(buf, off, flen);
buf[off++] = (byte)0x81;
off = Common.writeLength(buf, off, modulus_size);
off += rsapub.getModulus(buf, off);
buf[off++] = (byte)0x82;
off = Common.writeLength(buf, off, exponent_size);
off += rsapub.getExponent(buf, off);
return off;
} else if(isEc()) {
final ECPublicKey ecpub = (ECPublicKey)pub;
final short qsize = (short)(1 + 2 * (short)((ecpub.getSize() / 8) + (((ecpub.getSize() % 8) == 0) ? 0 : 1)));
short rsize = (short)(1 + qsize);
if(qsize > 0x7f) {
rsize = (short)(rsize + 2);
} else {
rsize = (short)(rsize + 1);
}
off = Common.writeLength(buf, off, rsize);
buf[off++] = (byte)0x86;
off = Common.writeLength(buf, off, qsize);
off += ecpub.getW(buf, off);
return off;
}
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return off;
}
protected final short sign(final byte[] buf, final short lc,
final boolean forAuth) {
if(!isInitialized()) {
ISOException.throwIt(Constants.SW_REFERENCE_DATA_NOT_FOUND);
return 0;
}
final PrivateKey priv = keys.getPrivate();
short off = 0;
byte[] sha_header = null;
if(isRsa()) {
if(!forAuth) {
if(lc == (short)(2 + Constants.DSI_SHA224_HEADER[1])) {
sha_header = Constants.DSI_SHA224_HEADER;
} else if(lc == (short)(2 + Constants.DSI_SHA256_HEADER[1])) {
sha_header = Constants.DSI_SHA256_HEADER;
} else if(lc == (short)(2 + Constants.DSI_SHA384_HEADER[1])) {
sha_header = Constants.DSI_SHA384_HEADER;
} else if(lc == (short)(2 + Constants.DSI_SHA512_HEADER[1])) {
sha_header = Constants.DSI_SHA512_HEADER;
} else {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return 0;
}
if(Util.arrayCompare(buf, (short)0, sha_header, (short)0, (byte)sha_header.length) != 0) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return 0;
}
}
if(lc > (short)(((short)(Common.bitsToBytes(rsaModulusBitSize()) * 2)) / 5)) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return 0;
}
final Cipher cipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
cipher.init(priv, Cipher.MODE_ENCRYPT);
off = cipher.doFinal(buf, (short)0, lc,
buf, (short)lc);
return Util.arrayCopyNonAtomic(buf, (short)lc,
buf, (short)0,
off);
} else if(isEc()) {
byte alg;
if(lc == MessageDigest.LENGTH_SHA) {
alg = Signature.ALG_ECDSA_SHA;
} else if(lc == MessageDigest.LENGTH_SHA_224) {
alg = Signature.ALG_ECDSA_SHA_224;
} else if(lc == MessageDigest.LENGTH_SHA_256) {
alg = Signature.ALG_ECDSA_SHA_256;
} else if(lc == MessageDigest.LENGTH_SHA_384) {
alg = Signature.ALG_ECDSA_SHA_384;
} else if(lc == MessageDigest.LENGTH_SHA_512) {
alg = Signature.ALG_ECDSA_SHA_512;
} else {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return 0;
}
final Signature sig = Signature.getInstance(alg, false);
sig.init(priv, Signature.MODE_SIGN);
final short sig_size = sig.signPreComputedHash(buf, (short)0, lc,
buf, lc);
off = (short)(lc + 1);
if((buf[off] & (byte)0x80) != (byte)0) {
++off;
}
++off;
if((buf[off++] != (byte)0x02)) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
if((buf[off] & (byte)0x80) != (byte)0) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
final short r_size = Util.makeShort((byte)0, buf[off++]);
final short r_off = off;
off += r_size;
if((buf[off++] != (byte)0x02)) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
if((buf[off] & (byte)0x80) != (byte)0) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
final short s_size = Util.makeShort((byte)0, buf[off++]);
final short s_off = off;
off = (short)(lc + sig_size);
if(r_size < s_size) {
off = Util.arrayFillNonAtomic(buf, off, (short)(s_size - r_size), (byte)0);
}
off = Util.arrayCopyNonAtomic(buf, r_off,
buf, off, r_size);
if(s_size < r_size) {
off = Util.arrayFillNonAtomic(buf, off, (short)(r_size - s_size), (byte)0);
}
off = Util.arrayCopyNonAtomic(buf, s_off,
buf, off, s_size);
off = Util.arrayCopyNonAtomic(buf, (short)(lc + sig_size),
buf, (short)0,
(short)(off - lc - sig_size));
Util.arrayFillNonAtomic(buf, off, (short)(lc + sig_size - off), (byte)0);
return off;
}
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return 0;
}
protected final short decipher(final ECCurves ec, final byte[] buf, final short lc) {
if(!isInitialized()) {
ISOException.throwIt(Constants.SW_REFERENCE_DATA_NOT_FOUND);
return 0;
}
final PrivateKey priv = keys.getPrivate();
short off = 0;
if(isRsa()) {
final short modulus_size = Common.bitsToBytes(rsaModulusBitSize());
if(lc != (short)(modulus_size + 1)) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
return 0;
}
if(buf[0] != (byte)0) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
final Cipher cipher = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
cipher.init(priv, Cipher.MODE_DECRYPT);
final short len = cipher.doFinal(buf, (short)1, (short)(lc - 1),
buf, (short)lc);
off = Util.arrayCopyNonAtomic(buf, lc,
buf, (short)0,
len);
Util.arrayFillNonAtomic(buf, lc, len, (byte)0);
return off;
} else if(isEc()) {
final ECParams params = ecParams(ec);
if((lc <= 7) || (lc > (short)(7 + 1 + (short)(2 * Common.bitsToBytes(params.nb_bits))))) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
if(buf[off] != (byte)0xA6) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
++off;
if(buf[off] != (byte)(lc - off - 1)) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
return 0;
}
++off;
if(Util.getShort(buf, off) != (short)(0x7f49)) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
off += 2;
if(buf[off] != (byte)(lc - off - 1)) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
return 0;
}
++off;
if(buf[off] != (byte)0x86) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
++off;
if(buf[off] != (byte)(lc - off - 1)) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
return 0;
}
++off;
final KeyAgreement ka = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DHC_PLAIN, false);
ka.init(priv);
final short len = ka.generateSecret(buf, off, (short)(lc - off),
buf, lc);
off = Util.arrayCopyNonAtomic(buf, lc,
buf, (short)0,
len);
Util.arrayFillNonAtomic(buf, lc, len, (byte)0);
return off;
}
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return 0;
}
protected final void initSignature(final Signature sign) {
if(!isInitialized()) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return;
}
sign.init(keys.getPrivate(), Signature.MODE_SIGN);
}
protected final void initKeyAgreement(final KeyAgreement ka) {
if(!isInitialized()) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return;
}
ka.init(keys.getPrivate());
}
}

View File

@@ -0,0 +1,233 @@
/*
SmartPGP : JavaCard implementation of OpenPGP card v3 specification
https://github.com/ANSSI-FR/smartpgp
Copyright (C) 2016 ANSSI
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 fr.anssi.smartpgp;
import javacard.framework.*;
import javacard.security.*;
import javacardx.apdu.*;
import javacardx.crypto.*;
public final class Persistent {
protected boolean isTerminated;
protected final byte[] login;
protected short login_length;
protected final byte[] url;
protected short url_length;
protected final PGPKey[] pgp_keys;
protected static final byte PGP_KEYS_OFFSET_SIG = 0;
protected static final byte PGP_KEYS_OFFSET_DEC = PGP_KEYS_OFFSET_SIG + 1;
protected static final byte PGP_KEYS_OFFSET_AUT = PGP_KEYS_OFFSET_DEC + 1;
private static final byte PGP_KEYS_LENGTH = PGP_KEYS_OFFSET_AUT + 1;
protected final Fingerprint[] fingerprints;
protected static final byte FINGERPRINTS_OFFSET_CA = 0;
protected static final byte FINGERPRINTS_OFFSET_CB = FINGERPRINTS_OFFSET_CA + 1;
protected static final byte FINGERPRINTS_OFFSET_CC = FINGERPRINTS_OFFSET_CB + 1;
private static final byte FINGERPRINTS_LENGTH = FINGERPRINTS_OFFSET_CC + 1;
protected final byte[] name;
protected byte name_length;
protected final byte[] lang;
protected byte lang_length;
protected byte sex;
protected byte[] digital_signature_counter;
protected byte[] do_0101;
protected short do_0101_length;
protected byte[] do_0102;
protected short do_0102_length;
protected byte[] do_0103;
protected short do_0103_length;
protected byte[] do_0104;
protected short do_0104_length;
protected AESKey aes_key;
protected final OwnerPIN user_pin; /* PW1 */
protected byte user_pin_length;
protected boolean user_pin_force_verify_signature;
protected final OwnerPIN user_puk; /* resetting code */
protected byte user_puk_length;
protected final OwnerPIN admin_pin; /* PW3 */
protected byte admin_pin_length;
protected Persistent() {
login = new byte[Constants.specialDoMaxLength()];
login_length = 0;
url = new byte[Constants.specialDoMaxLength()];
url_length = 0;
fingerprints = new Fingerprint[FINGERPRINTS_LENGTH];
for(byte i = 0; i < fingerprints.length; ++i) {
fingerprints[i] = new Fingerprint();
}
name = new byte[Constants.NAME_MAX_LENGTH];
name_length = 0;
lang = new byte[Constants.LANG_MAX_LENGTH];
lang_length = 0;
digital_signature_counter = new byte[3];
do_0101 = new byte[Constants.specialDoMaxLength()];
do_0101_length = 0;
do_0102 = new byte[Constants.specialDoMaxLength()];
do_0101_length = 0;
do_0103 = new byte[Constants.specialDoMaxLength()];
do_0103_length = 0;
do_0104 = new byte[Constants.specialDoMaxLength()];
do_0104_length = 0;
aes_key = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES,
(short)(Constants.aesKeyLength() * 8),
false);
pgp_keys = new PGPKey[PGP_KEYS_LENGTH];
for(byte i = 0; i < pgp_keys.length; ++i) {
pgp_keys[i] = new PGPKey(false);
}
user_pin = new OwnerPIN(Constants.USER_PIN_RETRY_COUNT, Constants.USER_PIN_MAX_SIZE);
user_puk = new OwnerPIN(Constants.USER_PUK_RETRY_COUNT, Constants.USER_PUK_MAX_SIZE);
admin_pin = new OwnerPIN(Constants.ADMIN_PIN_RETRY_COUNT, Constants.ADMIN_PIN_MAX_SIZE);
reset();
}
protected void reset() {
for(byte i = 0; i < pgp_keys.length; ++i) {
pgp_keys[i].reset();
}
if(login_length > 0) {
JCSystem.beginTransaction();
Util.arrayFillNonAtomic(login, (short)0, login_length, (byte)0);
login_length = (short)0;
JCSystem.commitTransaction();
}
if(url_length > 0) {
JCSystem.beginTransaction();
Util.arrayFillNonAtomic(url, (short)0, url_length, (byte)0);
url_length = (short)0;
JCSystem.commitTransaction();
}
for(byte i = 0; i < fingerprints.length; ++i) {
fingerprints[i].reset();
}
if(name_length > 0) {
JCSystem.beginTransaction();
Util.arrayFillNonAtomic(name, (short)0, name_length, (byte)0);
name_length = (byte)0;
JCSystem.commitTransaction();
}
JCSystem.beginTransaction();
if(lang_length > 0) {
Util.arrayFillNonAtomic(lang, (short)0, lang_length, (byte)0);
}
Util.arrayCopyNonAtomic(Constants.LANG_DEFAULT, (short)0, lang, (short)0, (short)Constants.LANG_DEFAULT.length);
lang_length = (byte)Constants.LANG_DEFAULT.length;
JCSystem.commitTransaction();
sex = Constants.SEX_NOT_ANNOUNCED;
Util.arrayFillNonAtomic(digital_signature_counter, (short)0,
(short)digital_signature_counter.length, (byte)0);
JCSystem.beginTransaction();
if(do_0101_length > 0) {
Util.arrayFillNonAtomic(do_0101, (short)0,
(short)do_0101.length, (byte)0);
do_0101_length = 0;
}
JCSystem.commitTransaction();
JCSystem.beginTransaction();
if(do_0102_length > 0) {
Util.arrayFillNonAtomic(do_0102, (short)0,
(short)do_0102.length, (byte)0);
do_0102_length = 0;
}
JCSystem.commitTransaction();
JCSystem.beginTransaction();
if(do_0103_length > 0) {
Util.arrayFillNonAtomic(do_0103, (short)0,
(short)do_0103.length, (byte)0);
do_0103_length = 0;
}
JCSystem.commitTransaction();
JCSystem.beginTransaction();
if(do_0104_length > 0) {
Util.arrayFillNonAtomic(do_0104, (short)0,
(short)do_0104.length, (byte)0);
do_0104_length = 0;
}
JCSystem.commitTransaction();
aes_key.clearKey();
user_pin_force_verify_signature = Constants.USER_PIN_DEFAULT_FORCE_VERIFY_SIGNATURE;
JCSystem.beginTransaction();
user_pin_length = (byte)Constants.USER_PIN_DEFAULT.length;
user_pin.update(Constants.USER_PIN_DEFAULT, (short)0, user_pin_length);
user_pin.resetAndUnblock();
JCSystem.commitTransaction();
user_puk_length = 0;
JCSystem.beginTransaction();
admin_pin_length = (byte)Constants.ADMIN_PIN_DEFAULT.length;
admin_pin.update(Constants.ADMIN_PIN_DEFAULT, (short)0, admin_pin_length);
admin_pin.resetAndUnblock();
JCSystem.commitTransaction();
isTerminated = false;
}
}

View File

@@ -0,0 +1,440 @@
/*
SmartPGP : JavaCard implementation of OpenPGP card v3 specification
https://github.com/ANSSI-FR/smartpgp
Copyright (C) 2016 ANSSI
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 fr.anssi.smartpgp;
import javacard.framework.*;
import javacard.security.*;
import javacardx.apdu.*;
import javacardx.crypto.*;
public final class SecureMessaging {
public static final short MAC_LENGTH = (short)(Constants.AES_BLOCK_SIZE / (short)2);
protected static final byte[] PADDING_BLOCK = {
(byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00
};
private final byte[] iv;
private final byte[] mac_chaining;
private final Cipher cipher;
private final AESKey senc;
private final CmacSignature macer;
private final CmacKey smac;
private final CmacKey srmac;
private final CmacKey sreceiptmac;
protected final PGPKey static_key;
protected SecureMessaging(final Transients transients) {
cipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
macer = new CmacSignature();
iv = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE,
JCSystem.CLEAR_ON_DESELECT);
mac_chaining = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE,
JCSystem.CLEAR_ON_DESELECT);
senc = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT,
(short)(Constants.aesKeyLength() * 8),
false);
smac = new CmacKey();
srmac = new CmacKey();
sreceiptmac = new CmacKey();
static_key = new PGPKey(true);
reset(transients);
}
protected final void clearSession(final Transients transients) {
senc.clearKey();
smac.clearKey();
srmac.clearKey();
sreceiptmac.clearKey();
macer.clear();
transients.setSecureMessagingEncryptionCounter((short)0);
Util.arrayFillNonAtomic(iv, (short)0, (short)iv.length, (byte)0);
Util.arrayFillNonAtomic(mac_chaining, (short)0, (short)mac_chaining.length, (byte)0);
}
protected final void reset(final Transients transients) {
clearSession(transients);
static_key.reset();
}
protected final boolean isInitialized() {
return static_key.isInitialized();
}
protected final boolean isSessionAvailable() {
return isInitialized()
&& senc.isInitialized()
&& smac.isInitialized()
&& srmac.isInitialized();
}
private final short scp11b(final ECParams params,
final byte[] buf, final short len) {
final byte[] crt = new byte[]{ (byte)0xA6, (byte)0x0D,
(byte)0x90, (byte)0x02, (byte)0x11, (byte)0x00,
(byte)0x95, (byte)0x01, (byte)0x3C,
(byte)0x80, (byte)0x01, (byte)0x88,
(byte)0x81, (byte)0x01 };
if(len <= (short)((short)crt.length + 4)) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
if(Util.arrayCompare(crt, (short)0,
buf, (short)0,
(short)crt.length) != (byte)0) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
short off = (short)crt.length;
if(buf[off] != Constants.aesKeyLength()) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return 0;
}
++off;
if(Util.getShort(buf, off) != (short)0x5F49) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
off += 2;
final short keylen = Common.readLength(buf, off, len);
off = Common.skipLength(buf, off, len);
if((short)(off + keylen) > len) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
return 0;
}
if(keylen != (short)(2 * Common.bitsToBytes(params.nb_bits) + 1)) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
return 0;
}
final ECPrivateKey eskcard = (ECPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE,
params.nb_bits,
false);
final ECPublicKey epkcard = (ECPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC,
params.nb_bits,
false);
params.setParams(eskcard);
params.setParams(epkcard);
final KeyPair ekcard = new KeyPair(epkcard, eskcard);
ekcard.genKeyPair();
if(!eskcard.isInitialized() ||
!epkcard.isInitialized()) {
ISOException.throwIt(Constants.SW_MEMORY_FAILURE);
return 0;
}
final KeyAgreement ka = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DHC_PLAIN, false);
ka.init(eskcard);
short msglen = 0;
msglen += ka.generateSecret(buf, off, keylen, buf, len);
eskcard.clearKey();
static_key.initKeyAgreement(ka);
msglen += ka.generateSecret(buf, off, keylen, buf, (short)(len + msglen));
Util.setShort(buf, (short)(len + msglen), (short)0);
msglen += 2;
short counter = 1;
off = (short)(len + msglen);
msglen += 2;
buf[(short)(len + msglen)] = crt[(short)8];
++msglen;
buf[(short)(len + msglen)] = crt[(short)11];
++msglen;
buf[(short)(len + msglen)] = buf[crt.length];
++msglen;
short keydata_len = 0;
final MessageDigest digest = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
while(keydata_len < (short)(4 * buf[crt.length])) {
Util.setShort(buf, off, counter);
++counter;
keydata_len += digest.doFinal(buf, len, msglen,
buf, (short)(len + msglen + keydata_len));
}
sreceiptmac.setKey(buf, (short)(len + msglen));
senc.setKey(buf, (short)(len + msglen + Constants.aesKeyLength()));
smac.setKey(buf, (short)(len + msglen + 2 * Constants.aesKeyLength()));
srmac.setKey(buf, (short)(len + msglen + 3 * Constants.aesKeyLength()));
Util.arrayFillNonAtomic(buf, len, (short)(msglen + keydata_len), (byte)0);
off = len;
Util.setShort(buf, off, (short)0x5F49);
off += 2;
off = Common.writeLength(buf, off, (short)(2 * Common.bitsToBytes(params.nb_bits) + 1));
off += epkcard.getW(buf, off);
msglen = off;
epkcard.clearKey();
buf[off++] = (byte)0x86;
buf[off++] = (byte)Constants.AES_BLOCK_SIZE;
macer.init(sreceiptmac);
macer.sign(buf, (short)0, msglen,
buf, off, Constants.AES_BLOCK_SIZE);
sreceiptmac.clearKey();
macer.clear();
Util.arrayCopy(buf, off, mac_chaining, (short)0, Constants.AES_BLOCK_SIZE);
off += Constants.AES_BLOCK_SIZE;
msglen = (short)(off - len);
Util.arrayCopy(buf, len, buf, (short)0, msglen);
return msglen;
}
protected final short establish(final Transients transients,
final ECCurves ec,
final byte[] buf, final short len) {
clearSession(transients);
if(isInitialized() && static_key.isEc()) {
final ECParams params = static_key.ecParams(ec);
if(params != null) {
if(((short)(Constants.aesKeyLength() * 8) == (short)128) ||
(params.nb_bits >= 512)) {
return scp11b(params, buf, len);
}
}
}
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return 0;
}
private final void incrementEncryptionCounter(final Transients transients) {
final short pval = transients.secureMessagingEncryptionCounter();
final short nval = (short)(pval + 1);
if(nval <= pval) {
clearSession(transients);
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
return;
}
transients.setSecureMessagingEncryptionCounter(nval);
}
protected final short verifyAndDecryptCommand(final Transients transients,
short dataLen, short dataWithHeaderLen) {
if(!isSessionAvailable()) {
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
return 0;
}
incrementEncryptionCounter(transients);
if(dataLen < MAC_LENGTH) {
clearSession(transients);
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
return 0;
}
final byte[] buf = transients.buffer;
macer.init(smac);
macer.update(mac_chaining, (short)0, Constants.AES_BLOCK_SIZE);
macer.update(buf, dataLen, (short)(dataWithHeaderLen - dataLen));
macer.sign(buf, (short)0, (short)(dataLen - MAC_LENGTH),
buf, dataLen, Constants.AES_BLOCK_SIZE);
if(Util.arrayCompare(buf, (short)(dataLen - MAC_LENGTH),
buf, dataLen,
MAC_LENGTH) != (byte)0) {
clearSession(transients);
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
return 0;
}
Util.arrayCopyNonAtomic(buf, dataLen,
mac_chaining, (short)0,
Constants.AES_BLOCK_SIZE);
dataLen -= MAC_LENGTH;
if(dataLen > 0) {
Util.arrayFillNonAtomic(buf, dataLen, Constants.AES_BLOCK_SIZE, (byte)0);
Util.setShort(buf, (short)(dataLen + Constants.AES_BLOCK_SIZE - 2),
transients.secureMessagingEncryptionCounter());
cipher.init(senc, Cipher.MODE_ENCRYPT);
cipher.doFinal(buf, dataLen, Constants.AES_BLOCK_SIZE,
iv, (short)0);
cipher.init(senc, Cipher.MODE_DECRYPT,
iv, (short)0, Constants.AES_BLOCK_SIZE);
short tmp = (short)(Constants.INTERNAL_BUFFER_MAX_LENGTH - dataLen);
if(tmp < Constants.AES_BLOCK_SIZE) {
ISOException.throwIt(Constants.SW_MEMORY_FAILURE);
return 0;
}
Util.arrayCopyNonAtomic(buf, (short)0,
buf, tmp,
dataLen);
dataLen = 0;
while(tmp < Constants.INTERNAL_BUFFER_MAX_LENGTH) {
if((short)(Constants.INTERNAL_BUFFER_MAX_LENGTH - tmp) <= Constants.AES_BLOCK_SIZE) {
dataLen += cipher.doFinal(buf, tmp, (short)(Constants.INTERNAL_BUFFER_MAX_LENGTH - tmp),
buf, dataLen);
tmp = Constants.INTERNAL_BUFFER_MAX_LENGTH;
} else {
dataLen += cipher.update(buf, tmp, Constants.AES_BLOCK_SIZE,
buf, dataLen);
tmp += Constants.AES_BLOCK_SIZE;
}
}
Util.arrayFillNonAtomic(iv, (short)0, (short)iv.length, (byte)0);
--dataLen;
while((dataLen > 0) && buf[dataLen] == (byte)0)
--dataLen;
if((dataLen <= 0) || (buf[dataLen] != (byte)0x80)) {
clearSession(transients);
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
return 0;
}
}
return dataLen;
}
protected final short encryptAndSign(final Transients transients,
short dataLen,
final short sw) {
if(!isSessionAvailable()) {
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
return 0;
}
final byte[] buf = transients.buffer;
if(dataLen > 0) {
Util.arrayFillNonAtomic(buf, dataLen, Constants.AES_BLOCK_SIZE, (byte)0);
buf[dataLen] = (byte)0x80;
Util.setShort(buf, (short)(dataLen + Constants.AES_BLOCK_SIZE - 2),
transients.secureMessagingEncryptionCounter());
cipher.init(senc, Cipher.MODE_ENCRYPT);
cipher.doFinal(buf, dataLen, Constants.AES_BLOCK_SIZE,
iv, (short)0);
cipher.init(senc, Cipher.MODE_ENCRYPT,
iv, (short)0, Constants.AES_BLOCK_SIZE);
short tmp = (short)(Constants.INTERNAL_BUFFER_MAX_LENGTH - dataLen);
if(tmp < Constants.AES_BLOCK_SIZE) {
ISOException.throwIt(Constants.SW_MEMORY_FAILURE);
return 0;
}
Util.arrayCopyNonAtomic(buf, (short)0,
buf, tmp,
dataLen);
dataLen = 0;
while(tmp < Constants.INTERNAL_BUFFER_MAX_LENGTH) {
if((short)(Constants.INTERNAL_BUFFER_MAX_LENGTH - tmp) <= Constants.AES_BLOCK_SIZE) {
dataLen += cipher.doFinal(buf, tmp, (short)(Constants.INTERNAL_BUFFER_MAX_LENGTH - tmp),
buf, dataLen);
tmp = Constants.INTERNAL_BUFFER_MAX_LENGTH;
} else {
dataLen += cipher.update(buf, tmp, Constants.AES_BLOCK_SIZE,
buf, dataLen);
tmp += Constants.AES_BLOCK_SIZE;
}
}
Util.arrayFillNonAtomic(iv, (short)0, (short)iv.length, (byte)0);
}
macer.init(srmac);
macer.update(mac_chaining, (short)0, Constants.AES_BLOCK_SIZE);
if(dataLen > 0) {
macer.update(buf, (short)0, dataLen);
}
macer.updateShort(sw);
dataLen += macer.sign(null, (short)0, (short)0,
buf, dataLen, MAC_LENGTH);
return dataLen;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,188 @@
/*
SmartPGP : JavaCard implementation of OpenPGP card v3 specification
https://github.com/ANSSI-FR/smartpgp
Copyright (C) 2016 ANSSI
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 fr.anssi.smartpgp;
import javacard.framework.*;
public final class Transients {
protected final byte[] buffer;
private final short[] shorts;
private static final byte SHORT_OFFSET_CURRENT_TAG = 0;
private static final byte SHORT_OFFSET_OUTPUT_START = SHORT_OFFSET_CURRENT_TAG + 1;
private static final byte SHORT_OFFSET_OUTPUT_LENGTH = SHORT_OFFSET_OUTPUT_START + 1;
private static final byte SHORT_OFFSET_CHAINING_INPUT_LENGTH = SHORT_OFFSET_OUTPUT_LENGTH + 1;
private static final byte SHORT_OFFSET_SECURE_MESSAGING_ENCRYPTION_COUNTER = SHORT_OFFSET_CHAINING_INPUT_LENGTH + 1;
private static final byte SHORTS_SIZE = SHORT_OFFSET_SECURE_MESSAGING_ENCRYPTION_COUNTER + 1;
private final byte[] bytes;
private static final byte BYTE_OFFSET_CHAINING_INPUT_INS = 0;
private static final byte BYTE_OFFSET_CHAINING_INPUT_P1 = BYTE_OFFSET_CHAINING_INPUT_INS + 1;
private static final byte BYTE_OFFSET_CHAINING_INPUT_P2 = BYTE_OFFSET_CHAINING_INPUT_P1 + 1;
private static final byte BYTE_OFFSET_CURRENT_TAG_OCCURRENCE = BYTE_OFFSET_CHAINING_INPUT_P2 + 1;
private static final byte BYTES_SIZE = BYTE_OFFSET_CURRENT_TAG_OCCURRENCE + 1;
private final boolean[] booleans;
private static final byte BOOLEAN_OFFSET_CHAINING_OUTPUT = 0;
private static final byte BOOLEAN_OFFSET_CHAINING_INPUT = BOOLEAN_OFFSET_CHAINING_OUTPUT + 1;
private static final byte BOOLEAN_OFFSET_USER_PIN_MODE_81 = BOOLEAN_OFFSET_CHAINING_INPUT + 1;
private static final byte BOOLEAN_OFFSET_USER_PIN_MODE_82 = BOOLEAN_OFFSET_USER_PIN_MODE_81 + 1;
private static final byte BOOLEAN_OFFSET_SECURE_MESSAGING_OK = BOOLEAN_OFFSET_USER_PIN_MODE_82 + 1;
private static final byte BOOLEANS_SIZE = BOOLEAN_OFFSET_SECURE_MESSAGING_OK + 1;
protected Transients() {
buffer = JCSystem.makeTransientByteArray(Constants.INTERNAL_BUFFER_MAX_LENGTH,
JCSystem.CLEAR_ON_DESELECT);
shorts = JCSystem.makeTransientShortArray(SHORTS_SIZE,
JCSystem.CLEAR_ON_DESELECT);
bytes = JCSystem.makeTransientByteArray(BYTES_SIZE,
JCSystem.CLEAR_ON_DESELECT);
booleans = JCSystem.makeTransientBooleanArray(BOOLEANS_SIZE,
JCSystem.CLEAR_ON_DESELECT);
}
protected final void clear() {
for(byte i = 0; i < shorts.length; ++i) {
shorts[i] = (short)0;
}
for(byte i = 0; i < bytes.length; ++i) {
bytes[i] = (byte)0;
}
for(byte i = 0; i < booleans.length; ++i) {
booleans[i] = false;
}
}
protected final void setCurrentTag(final short tag) {
shorts[SHORT_OFFSET_CURRENT_TAG] = tag;
}
protected final short currentTag() {
return shorts[SHORT_OFFSET_CURRENT_TAG];
}
protected final void setChainingInputLength(final short len) {
shorts[SHORT_OFFSET_CHAINING_INPUT_LENGTH] = len;
}
protected final short chainingInputLength() {
return shorts[SHORT_OFFSET_CHAINING_INPUT_LENGTH];
}
protected final void setSecureMessagingEncryptionCounter(final short val) {
shorts[SHORT_OFFSET_SECURE_MESSAGING_ENCRYPTION_COUNTER] = val;
}
protected final short secureMessagingEncryptionCounter() {
return shorts[SHORT_OFFSET_SECURE_MESSAGING_ENCRYPTION_COUNTER];
}
protected final void setOutputStart(final short off) {
shorts[SHORT_OFFSET_OUTPUT_START] = off;
}
protected final short outputStart() {
return shorts[SHORT_OFFSET_OUTPUT_START];
}
protected final void setOutputLength(final short len) {
shorts[SHORT_OFFSET_OUTPUT_LENGTH] = len;
}
protected final short outputLength() {
return shorts[SHORT_OFFSET_OUTPUT_LENGTH];
}
protected final void setChainingInputIns(final byte ins) {
bytes[BYTE_OFFSET_CHAINING_INPUT_INS] = ins;
}
protected final byte chainingInputIns() {
return bytes[BYTE_OFFSET_CHAINING_INPUT_INS];
}
protected final void setChainingInputP1(final byte p1) {
bytes[BYTE_OFFSET_CHAINING_INPUT_P1] = p1;
}
protected final byte chainingInputP1() {
return bytes[BYTE_OFFSET_CHAINING_INPUT_P1];
}
protected final void setChainingInputP2(final byte p2) {
bytes[BYTE_OFFSET_CHAINING_INPUT_P2] = p2;
}
protected final byte chainingInputP2() {
return bytes[BYTE_OFFSET_CHAINING_INPUT_P2];
}
protected final void setCurrentTagOccurrence(final byte occ) {
bytes[BYTE_OFFSET_CURRENT_TAG_OCCURRENCE] = occ;
}
protected final byte currentTagOccurrence() {
return bytes[BYTE_OFFSET_CURRENT_TAG_OCCURRENCE];
}
protected final void setChainingOutput(final boolean chaining) {
booleans[BOOLEAN_OFFSET_CHAINING_OUTPUT] = chaining;
}
protected final boolean chainingOutput() {
return booleans[BOOLEAN_OFFSET_CHAINING_OUTPUT];
}
protected final void setChainingInput(final boolean chaining) {
booleans[BOOLEAN_OFFSET_CHAINING_INPUT] = chaining;
}
protected final boolean chainingInput() {
return booleans[BOOLEAN_OFFSET_CHAINING_INPUT];
}
protected final void setUserPinMode81(final boolean is81) {
booleans[BOOLEAN_OFFSET_USER_PIN_MODE_81] = is81;
}
protected final boolean userPinMode81() {
return booleans[BOOLEAN_OFFSET_USER_PIN_MODE_81];
}
protected final void setUserPinMode82(final boolean is82) {
booleans[BOOLEAN_OFFSET_USER_PIN_MODE_82] = is82;
}
protected final boolean userPinMode82() {
return booleans[BOOLEAN_OFFSET_USER_PIN_MODE_82];
}
protected final void setSecureMessagingOk(final boolean ok) {
booleans[BOOLEAN_OFFSET_SECURE_MESSAGING_OK] = ok;
}
protected final boolean secureMessagingOk() {
return booleans[BOOLEAN_OFFSET_SECURE_MESSAGING_OK];
}
}