Initial commit
This commit is contained in:
81
src/fr/anssi/smartpgp/CmacKey.java
Normal file
81
src/fr/anssi/smartpgp/CmacKey.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
229
src/fr/anssi/smartpgp/CmacSignature.java
Normal file
229
src/fr/anssi/smartpgp/CmacSignature.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
138
src/fr/anssi/smartpgp/Common.java
Normal file
138
src/fr/anssi/smartpgp/Common.java
Normal 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++]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
240
src/fr/anssi/smartpgp/Constants.java
Normal file
240
src/fr/anssi/smartpgp/Constants.java
Normal 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;
|
||||
|
||||
}
|
605
src/fr/anssi/smartpgp/ECConstants.java
Normal file
605
src/fr/anssi/smartpgp/ECConstants.java
Normal 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
|
||||
};
|
||||
|
||||
|
||||
}
|
116
src/fr/anssi/smartpgp/ECCurves.java
Normal file
116
src/fr/anssi/smartpgp/ECCurves.java
Normal 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;
|
||||
}
|
||||
}
|
67
src/fr/anssi/smartpgp/ECParams.java
Normal file
67
src/fr/anssi/smartpgp/ECParams.java
Normal 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);
|
||||
}
|
||||
}
|
50
src/fr/anssi/smartpgp/Fingerprint.java
Normal file
50
src/fr/anssi/smartpgp/Fingerprint.java
Normal 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);
|
||||
}
|
||||
}
|
848
src/fr/anssi/smartpgp/PGPKey.java
Normal file
848
src/fr/anssi/smartpgp/PGPKey.java
Normal 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());
|
||||
}
|
||||
|
||||
}
|
233
src/fr/anssi/smartpgp/Persistent.java
Normal file
233
src/fr/anssi/smartpgp/Persistent.java
Normal 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;
|
||||
}
|
||||
}
|
440
src/fr/anssi/smartpgp/SecureMessaging.java
Normal file
440
src/fr/anssi/smartpgp/SecureMessaging.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
1516
src/fr/anssi/smartpgp/SmartPGPApplet.java
Normal file
1516
src/fr/anssi/smartpgp/SmartPGPApplet.java
Normal file
File diff suppressed because it is too large
Load Diff
188
src/fr/anssi/smartpgp/Transients.java
Normal file
188
src/fr/anssi/smartpgp/Transients.java
Normal 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];
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user