Smart Card Solution
User Manual
- R502 Manual
JavaCard API Samples
- Algorithm
Java Card Specification
Knowledge Sharing
Smart Card Solution
User Manual
JavaCard API Samples
Java Card Specification
Knowledge Sharing
This is an old revision of the document!
Download Sample Code Discussion
/* * @file RSASample.java * @version v1.0 * Package AID: 4A617661436172644F53 * Applet AID: 4A617661436172644F5303 * @brief The ALgorithm of RSA Sample Code in JavaCard API Specification * @comment The purpose of this example is only used to show the usage of API functions and there is no practical significance. * @copyright Copyright(C) 2016 JavaCardOS Technologies Co., Ltd. All rights reserved. */ package JavaCardOS.Sample.Algorithm; import javacard.framework.*; import javacard.security.KeyBuilder; import javacard.security.*; import javacardx.crypto.*; public class RSASample extends Applet { private static final byte INS_GEN_RSA_KEYPAIR = (byte)0x30; private static final byte INS_GET_RSA_PUBKEY = (byte)0x31; private static final byte INS_GET_RSA_PRIKEY = (byte)0x32; private static final byte INS_SET_RSA_PUBKEY = (byte)0x33; private static final byte INS_SET_RSA_PRIKEY = (byte)0x34; private static final byte INS_RSA_SIGN = (byte)0x35; private static final byte INS_RSA_VERIFY = (byte)0x36; private static final byte INS_DO_RSA_CIPHER = (byte)0x37; private byte[] tempBuffer; private byte[] flags; private static final short OFF_INS = (short)0; private static final short OFF_P1 = (short)1; private static final short OFF_P2 = (short)2; private static final short OFF_LEN = (short)3; private static final short FLAGS_SIZE = (short)5; private static final byte ID_N = 0; private static final byte ID_D = 1; private static final byte ID_P = 2; private static final byte ID_Q = 3; private static final byte ID_PQ = 4; private static final byte ID_DP1 = 5; private static final byte ID_DQ1 = 6; private byte[] rsaPubKey; private short rsaPubKeyLen; private byte[] rsaPriKey; private short rsaPriKeyLen; private boolean isRSAPriKeyCRT; private Cipher rsaCipher; private Signature rsaSignature; private static final short SW_REFERENCE_DATA_NOT_FOUND = (short)0x6A88; public RSASample() { //Create a transient byte array to store the temporary data tempBuffer = JCSystem.makeTransientByteArray((short)256, JCSystem.CLEAR_ON_DESELECT); flags = JCSystem.makeTransientByteArray(FLAGS_SIZE, JCSystem.CLEAR_ON_DESELECT); rsaPubKey = new byte[(short) (256 + 32)]; rsaPriKey = new byte[(short)(128 * 5)]; rsaPubKeyLen = 0; rsaPriKeyLen = 0; isRSAPriKeyCRT = false; rsaSignature = null; //Create a RSA(not pad) object instance rsaCipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false); JCSystem.requestObjectDeletion(); } public static void install(byte[] bArray, short bOffset, byte bLength) { new RSASample().register(bArray, (short) (bOffset + 1), bArray[bOffset]); } public void process(APDU apdu) { if (selectingApplet()) { return; } byte[] buf = apdu.getBuffer(); short len = apdu.setIncomingAndReceive(); switch (buf[ISO7816.OFFSET_INS]) { case INS_GEN_RSA_KEYPAIR: //GEN_RSA_KEYPAIR genRsaKeyPair(apdu, len); break; case INS_GET_RSA_PUBKEY: //GET_RSA_PUBKEY getRsaPubKey(apdu, len); break; case INS_GET_RSA_PRIKEY: //GET_RSA_PRIKEY getRsaPriKey(apdu, len); break; case INS_SET_RSA_PUBKEY: // SET_RSA_PUBKEY setRsaPubKey(apdu, len); break; case INS_SET_RSA_PRIKEY: //SET_RSA_PRIKEY setRsaPriKey(apdu, len); break; case INS_RSA_SIGN: //RSA_SIGN rsaSign(apdu, len); break; case INS_RSA_VERIFY: //RSA_VERIFY rsaVerify(apdu, len); break; case INS_DO_RSA_CIPHER: //RSA_CIPHER doRSACipher(apdu, len); break; default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); } } //RSA algorithm encrypt and decrypt private void doRSACipher(APDU apdu, short len) { byte[] buffer = apdu.getBuffer(); byte p1Tmp = buffer[ISO7816.OFFSET_P1]; boolean hasMoreCmd = (p1Tmp & 0x80) != 0; boolean isEncrypt = (p1Tmp & 0x01) != 1; short keyLen = (p1Tmp & 0x08) == (byte)0x00 ? KeyBuilder.LENGTH_RSA_1024 : KeyBuilder.LENGTH_RSA_2048; short offset = (p1Tmp & 0x08) == (byte)0x00 ? (short)128 : (short)256; if (len rsaPubKey.length) { Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0); ISOException.throwIt(ISO7816.SW_WRONG_DATA); } //Copy the value of RSA public key to the global variable 'rsaPubKey'. Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, rsaPubKey, loadedLen, len); loadedLen += len; if ((buffer[ISO7816.OFFSET_P1] & 0x80) == 0) //last block { Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0); short modLen = (buffer[ISO7816.OFFSET_P1] & 0x01) == 0 ? (short)128 : (short)256; if (loadedLen < modLen + 3 || loadedLen > modLen + 32) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } rsaPubKeyLen = loadedLen; } else { Util.setShort(flags, OFF_LEN, loadedLen); } } //Set the value of RSA private key private void setRsaPriKey(APDU apdu, short len) { byte[] buffer = apdu.getBuffer(); if (buffer[ISO7816.OFFSET_P2] == 0) // first block { rsaPriKeyLen = (short)0; Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_INS, flags, OFF_INS, (short)3); Util.setShort(flags, OFF_LEN, (short)0); } else { if (flags[OFF_INS] != buffer[ISO7816.OFFSET_INS] || (flags[OFF_P1] & 0x7f) != (buffer[ISO7816.OFFSET_P1] & 0x7f) || (short)(flags[OFF_P2] & 0xff) != (short)((buffer[ISO7816.OFFSET_P2] & 0xff) - 1)) { Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0); ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } flags[OFF_P2] ++; } short loadedLen = Util.getShort(flags, OFF_LEN); if (loadedLen + len > rsaPriKey.length) { Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0); ISOException.throwIt(ISO7816.SW_WRONG_DATA); } //Copy the value of RSA private key to the global variable 'rsaPriKey'. Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, rsaPriKey, loadedLen, len); loadedLen += len; if ((buffer[ISO7816.OFFSET_P1] & 0x80) == 0) //last block { Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0); short modLen = (buffer[ISO7816.OFFSET_P1] & 0x01) == 0 ? (short)128 : (short)256; boolean isCRT = (buffer[ISO7816.OFFSET_P1] & 0x40) != 0; if ((isCRT && (loadedLen != modLen / 2 * 5)) || (!isCRT && (loadedLen != modLen * 2))) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } isRSAPriKeyCRT = isCRT; rsaPriKeyLen = loadedLen; } else { Util.setShort(flags, OFF_LEN, loadedLen); } } // private void genRsaKeyPair(APDU apdu, short len) { byte[] buffer = apdu.getBuffer(); short keyLen = buffer[ISO7816.OFFSET_P1] == 0 ? (short)1024 : (short)2048; byte alg = buffer[ISO7816.OFFSET_P2] == 0 ? KeyPair.ALG_RSA : KeyPair.ALG_RSA_CRT; KeyPair keyPair = new KeyPair(alg, keyLen); if (len > 32) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } if (len > 0) { ((RSAPublicKey)keyPair.getPublic()).setExponent(buffer, ISO7816.OFFSET_CDATA, len); } //(Re)Initializes the key objects encapsulated in this KeyPair instance with new key values. keyPair.genKeyPair(); JCSystem.beginTransaction(); rsaPubKeyLen = 0; rsaPriKeyLen = 0; JCSystem.commitTransaction(); //Get a reference to the public key component of this 'keyPair' object. RSAPublicKey pubKey = (RSAPublicKey)keyPair.getPublic(); short pubKeyLen = 0; //Store the RSA public key value in the global variable 'rsaPubKey', the public key contains modulo N and Exponent E pubKeyLen += pubKey.getModulus(rsaPubKey, pubKeyLen); pubKeyLen += pubKey.getExponent(rsaPubKey, pubKeyLen); short priKeyLen = 0; if (alg == KeyPair.ALG_RSA) { isRSAPriKeyCRT = false; //Returns a reference to the private key component of this KeyPair object. RSAPrivateKey priKey = (RSAPrivateKey)keyPair.getPrivate(); //RSA Algorithm, the Private Key contains N and D, and store these parameters value in global variable 'rsaPriKey'. priKeyLen += priKey.getModulus(rsaPriKey, priKeyLen); priKeyLen += priKey.getExponent(rsaPriKey, priKeyLen); } else //RSA CRT { isRSAPriKeyCRT = true; //The RSAPrivateCrtKey interface is used to sign data using the RSA algorithm in its Chinese Remainder Theorem form. RSAPrivateCrtKey priKey = (RSAPrivateCrtKey)keyPair.getPrivate(); //RSA CRT Algorithm, the Private Key contains P Q PQ DP and DQ, and store these parameters value in global variable 'rsaPriKey'. priKeyLen += priKey.getP(rsaPriKey, priKeyLen); priKeyLen += priKey.getQ(rsaPriKey, priKeyLen); priKeyLen += priKey.getPQ(rsaPriKey, priKeyLen); priKeyLen += priKey.getDP1(rsaPriKey, priKeyLen); priKeyLen += priKey.getDQ1(rsaPriKey, priKeyLen); } JCSystem.beginTransaction(); rsaPubKeyLen = pubKeyLen; rsaPriKeyLen = priKeyLen; JCSystem.commitTransaction(); JCSystem.requestObjectDeletion(); } //RSA Signature private void rsaSign(APDU apdu, short len) { byte[] buffer = apdu.getBuffer(); if (rsaPriKeyLen == 0) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } boolean hasMoreCmd = (buffer[ISO7816.OFFSET_P1] & 0x80) != 0; short resultLen = 0; if (buffer[ISO7816.OFFSET_P2] == 0) //first block { Key key; if (!isRSAPriKeyCRT) { short ret; //Creates uninitialized private keys for signature algorithms. key = KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE, (short)(rsaPriKeyLen / 2 * 8), false); ret = getRsaPriKeyComponent(ID_N, tempBuffer, (short)0); ((RSAPrivateKey)key).setModulus(tempBuffer, (short)0, ret); ret = getRsaPriKeyComponent(ID_D, tempBuffer, (short)0); ((RSAPrivateKey)key).setExponent(tempBuffer, (short)0, ret); } else { short ret; //Creates uninitialized private keys for signature algorithms. key = KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_CRT_PRIVATE, (short)(rsaPriKeyLen / 5 * 16), false); ret = getRsaPriKeyComponent(ID_P, tempBuffer, (short)0); ((RSAPrivateCrtKey)key).setP(tempBuffer, (short)0, ret); ret = getRsaPriKeyComponent(ID_Q, tempBuffer, (short)0); ((RSAPrivateCrtKey)key).setQ(tempBuffer, (short)0, ret); ret = getRsaPriKeyComponent(ID_DP1, tempBuffer, (short)0); ((RSAPrivateCrtKey)key).setDP1(tempBuffer, (short)0, ret); ret = getRsaPriKeyComponent(ID_DQ1, tempBuffer, (short)0); ((RSAPrivateCrtKey)key).setDQ1(tempBuffer, (short)0, ret); ret = getRsaPriKeyComponent(ID_PQ, tempBuffer, (short)0); ((RSAPrivateCrtKey)key).setPQ(tempBuffer, (short)0, ret); } // Creates a Signature object instance of the ALG_RSA_SHA_PKCS1 algorithm. rsaSignature = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false); JCSystem.requestObjectDeletion(); //Initializ the Signature object. rsaSignature.init(key, Signature.MODE_SIGN); Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_INS, flags, OFF_INS, (short)3); JCSystem.requestObjectDeletion(); } else { if (flags[OFF_INS] != buffer[ISO7816.OFFSET_INS] || (flags[OFF_P1] & 0x7f) != (buffer[ISO7816.OFFSET_P1] & 0x7f) || (short)(flags[OFF_P2] & 0xff) != (short)((buffer[ISO7816.OFFSET_P2] & 0xff) - 1)) { Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0); ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } flags[OFF_P2] ++; } if (hasMoreCmd) { // Accumulates a signature of the input data. rsaSignature.update(buffer, ISO7816.OFFSET_CDATA, len); } else { //Generates the signature of all input data. short ret = rsaSignature.sign(buffer, ISO7816.OFFSET_CDATA, len, buffer, (short)0); Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0); apdu.setOutgoingAndSend((short)0, ret); } } //RSA Signature and Verify private void rsaVerify(APDU apdu, short len) { byte[] buffer = apdu.getBuffer(); if (rsaPubKeyLen == 0) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); } boolean hasMoreCmd = (buffer[ISO7816.OFFSET_P1] & 0x80) != 0; short resultLen = 0; short offset = ISO7816.OFFSET_CDATA; short modLen = rsaPubKeyLen > 256 ? (short)256 : (short)128; if (buffer[ISO7816.OFFSET_P2] == 0) //first block { Key key; // Create uninitialized public keys for signature algorithms. key = KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, (short)(modLen * 8), false); //Sets the modulus value of the key. ((RSAPublicKey)key).setModulus(rsaPubKey, (short)0, modLen); //Sets the public exponent value of the key. ((RSAPublicKey)key).setExponent(rsaPubKey, modLen, (short)(rsaPubKeyLen - modLen)); //Create a ALG_RSA_SHA_PKCS1 object instance. rsaSignature = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false); JCSystem.requestObjectDeletion(); //Initializes the Signature object with the appropriate Key. rsaSignature.init(key, Signature.MODE_VERIFY); Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_INS, flags, OFF_INS, (short)3); Util.setShort(flags, OFF_LEN, (short)0); JCSystem.requestObjectDeletion(); } else { if (flags[OFF_INS] != buffer[ISO7816.OFFSET_INS] || (flags[OFF_P1] & 0x7f) != (buffer[ISO7816.OFFSET_P1] & 0x7f) || (short)(flags[OFF_P2] & 0xff) != (short)((buffer[ISO7816.OFFSET_P2] & 0xff) - 1)) { Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0); ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); } flags[OFF_P2] ++; } short sigLen = Util.getShort(flags, OFF_LEN); if (sigLen < modLen) { short readLen = (short)(modLen - sigLen); if (readLen > len) { readLen = len; } Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, tempBuffer, sigLen, readLen); sigLen += readLen; len -= readLen; Util.setShort(flags, OFF_LEN, sigLen); offset += readLen; } if (hasMoreCmd) { if (len > 0) { //Accumulates a signature of the input data. rsaSignature.update(buffer, offset, len); } } else { if (sigLen != modLen) { Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0); ISOException.throwIt(ISO7816.SW_WRONG_DATA); } //Verify the signature of all/last input data against the passed in signature. boolean ret = rsaSignature.verify(buffer, offset, len, tempBuffer, (short)0, sigLen); Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0); buffer[(short)0] = ret ? (byte)1 : (byte)0; apdu.setOutgoingAndSend((short)0, (short)1); } } }
The test script of RSA is as follows: Download Test Script
//The test script of RSA //Copyright(C) JavaCardOS Technologies Co., Ltd. All rights reserved. //RSA Select Applet 00A404000B4A617661436172644F530300; //RSA //generate-keypair-1024 in card 80300000; //get Publck Key - N 80310000; //get Publck Key - E The data of response APDU command is 4 bytes, such as 01 00 01 90 00 80310100; //get RSA Private Key - N 80320000; //get RSA Private Key - D 80320100; //RSA encrypt - 2048 //set RSA Public key 2048bit 80338100C8C24A7A902FA8983CBBAB3F690528F86D5591496374E6B3B4EC47CA644CB55F204C4D5EEBBD9D236B6F74AC209738CB294A7C26F1251D838EDF8ADAF3E287743A5D7C65BBBCFE4A22BEB06D0D65DAFE1D1217E8AB9E5B7AA0D3883A4D6D2F5BE5B295AE6CD495D45D4452876F573C3EDD402E3BA998EC1078F662027A5F7BCE949C3B3F0309B1BE5EE9AAE720C97C2C2F0CBCD298E3FC049A457513DCCC70BDA06949011BC1F0DB6F499685377DF87B3E66890FB4C0CC09CF12DB338394C44E324D0F1931D623C035; 803301013BD00F518C353243CD22A3239811928163DCDA1352044AE4E15F10FEF648E98AE88B7BBA89F29C7EFAE5EE04E299F90F52FEE263AF2DA885FB010001; //set RSA Private Key 2048bit 80348100C8C24A7A902FA8983CBBAB3F690528F86D5591496374E6B3B4EC47CA644CB55F204C4D5EEBBD9D236B6F74AC209738CB294A7C26F1251D838EDF8ADAF3E287743A5D7C65BBBCFE4A22BEB06D0D65DAFE1D1217E8AB9E5B7AA0D3883A4D6D2F5BE5B295AE6CD495D45D4452876F573C3EDD402E3BA998EC1078F662027A5F7BCE949C3B3F0309B1BE5EE9AAE720C97C2C2F0CBCD298E3FC049A457513DCCC70BDA06949011BC1F0DB6F499685377DF87B3E66890FB4C0CC09CF12DB338394C44E324D0F1931D623C035; 80348101C8D00F518C353243CD22A3239811928163DCDA1352044AE4E15F10FEF648E98AE88B7BBA89F29C7EFAE5EE04E299F90F52FEE263AF2DA885FB8FFFDD79122995B3A5B0558E03CA0ADE1606596B42505EAEE0549117E796A18B71A202911C76E3B293E7D84F4B65478631F3747553F9DCF0BE93CE95E5B659198D024EF06731DD468528839AE37BFCCD1504ED688D34E5DD5F0A5F93D531BD9DAFCFAA7874D31B9388B8D6325A68877B3A3F49EEF82D364440F001402B96BA533404EB121B0E6604B0678A5AAA100C56; 8034010270B3ECD17EDDCB4F5BC71BBE1E7A405679380E6D9A777AA8452A2DE5F1FECAA09ACEA4A02940A14F28C7CBF7EE0A1A1519B58ED3161A590BC66B82C13CD43C484AD2D77E8301629F9B1EB4C7505C5A7B46C0171668990775FDF2E62BB695DF424130727CD0ACC61943FE8EF513A0AC9BD1; // RSA Signature SHA1 &2048bit //expect:75A78094B3A63715B85327C2839CE1E1831C39B740DDB9F67F27AEBC540DB94BF95C7DEE200AC60A2BF0F64B9F4772A163E036D8DC8E865EFD5B3E7A9442BDF43BA86660D305C15DB2A3A8F5F6E3D1F50E234B193DD787B89E3EDF045E280285474A027E8985F45D883E14593D91CF79017E3AEBCF8A155DD0B5C85BE0A4301D0F80C99A15D154DF54FFE8EB603DA85184386452ABB47C985EF1D5390FF74516A7F0B8A05380DD186AA6FA584287F8AAE6421D98AD84601D734EA008CE0B37FF574BD1C9FE948DABF0A78F4E691FC0A9CAE6DC1288BD2E295CFB31443F09AF16B5D66886BA7AEF2FF272E443ADBA47798F76EF6B4594CEC399526F21236AD3A29000 8035000080C05DECFACFC439CA7AB1EC89F554FF982FB7E8E95FFFC863DFEFE5883EAD5A5591C90D69097BE26ACB2C2EA5FB386FF41AF33AE593EA7418906BC5E912474A4F41D68A04013CACE7C5EBE79EA869397FBA545CB197A3F68E3F2E104C2171C9DD798C4B13DC8FFF0811F5FDBD236EC701B4E2369594B2B48D9341ACF993B33FC5; //RSA Verify 2048bit 80368000C875A78094B3A63715B85327C2839CE1E1831C39B740DDB9F67F27AEBC540DB94BF95C7DEE200AC60A2BF0F64B9F4772A163E036D8DC8E865EFD5B3E7A9442BDF43BA86660D305C15DB2A3A8F5F6E3D1F50E234B193DD787B89E3EDF045E280285474A027E8985F45D883E14593D91CF79017E3AEBCF8A155DD0B5C85BE0A4301D0F80C99A15D154DF54FFE8EB603DA85184386452ABB47C985EF1D5390FF74516A7F0B8A05380DD186AA6FA584287F8AAE6421D98AD84601D734EA008CE0B37FF574BD1C9FE948DAB; //expect:019000 80360001B8F0A78F4E691FC0A9CAE6DC1288BD2E295CFB31443F09AF16B5D66886BA7AEF2FF272E443ADBA47798F76EF6B4594CEC399526F21236AD3A2C05DECFACFC439CA7AB1EC89F554FF982FB7E8E95FFFC863DFEFE5883EAD5A5591C90D69097BE26ACB2C2EA5FB386FF41AF33AE593EA7418906BC5E912474A4F41D68A04013CACE7C5EBE79EA869397FBA545CB197A3F68E3F2E104C2171C9DD798C4B13DC8FFF0811F5FDBD236EC701B4E2369594B2B48D9341ACF993B33FC5; //RSA -2048 encrypt 80378800643E78AA266AA64FED361D907305CD70438AA5F0E674AAD69E5146AD57ACE20DDA79B71C44B4E055B644B4884F25542257C680AFBDB0AF9DC4695E43F998A8226869176A0F33BAC09359773E326EA3BBF99CD04D3746E60D31EC761A174F4AE137D6419B71; 8037880164315A16EB3C0EB90626E3C390D23ED33B7D78AD4D3E78AA266AA64FED361D907305CD70438AA5F0E674AAD69E5146AD57ACE20DDA79B71C44B4E055B644B4884F25542257C680AFBDB0AF9DC4695E43F998A8226869176A0F33BAC09359773E326EA3BBF9; //expect:50237853BC0EBF1537BACA8022795F75FBCF4DDAF18FB99464F68E2E29D7023159BE25219D4493EADB048811304301507EEECEEC0056665E77960D338B4AB52B00B2235E2CF390B1BFDB77716C82493D719228385B707D56DAB30C06661218F162181E90094E32C5D1879F1401B3B17CE961297977CA7C97B2C10FC0FF104780A360150C797EDFA60677C200AA78F3EDCC99FDA1BCE14961A65C4F41552EE575EFB07F4074C8071F80AE083F1AA2BFDB0007A824A7828BBFB583D96B6D6EAD84F9124CA9B7A41EC522630C605886E8EAD146A6C837ED88BC39D779541B5586B518F20554FF8D1496B9EB17A3954FBCB9F3E7C5B6F01DA8C973E4B41A96B32F5C9000 80370802389CD04D3746E60D31EC761A174F4AE137D6419B71315A16EB3C0EB90626E3C390D23ED33B7D78AD4DA2353B9A1AF1D2AFA2353B9A1AF1D2AF; //RSA -2048 decrypt 80378900C850237853BC0EBF1537BACA8022795F75FBCF4DDAF18FB99464F68E2E29D7023159BE25219D4493EADB048811304301507EEECEEC0056665E77960D338B4AB52B00B2235E2CF390B1BFDB77716C82493D719228385B707D56DAB30C06661218F162181E90094E32C5D1879F1401B3B17CE961297977CA7C97B2C10FC0FF104780A360150C797EDFA60677C200AA78F3EDCC99FDA1BCE14961A65C4F41552EE575EFB07F4074C8071F80AE083F1AA2BFDB0007A824A7828BBFB583D96B6D6EAD84F9124CA9B7A41EC5; 803709013822630C605886E8EAD146A6C837ED88BC39D779541B5586B518F20554FF8D1496B9EB17A3954FBCB9F3E7C5B6F01DA8C973E4B41A96B32F5C; //2048-CRT //set public Key RSA CRT-2048 80338100C8AF536A413B40AD9D363E2A8192986A4F054C1C4BE30D47EDD76A32D1AA7EE9A9F91E5BA81D20819B5A5293D8C39F8549E3695E13BE12B19405110D2FBED0E393016D231B4201408CDE963377F802579313ECBBB49320B09D8216374EC50A70D70AE1DE5E0E05AD1B7A1F57638674309FB544EB35CBB5535D3C4C727FF633C6CFFF44F0E141B38074B5C92EF26A57B173F3DDE85C5D4F0B2A3F06E4F1961BB07712D9D0B901EDC8CEA67AEDDBBA0C7EA08857B6934168AF893E7F419DE51E45EEF8272274D85F89D8; 803301013B95E867318D75FADC8AA35FC053B3E02EABA50B2D7B61F0F3EB7A4BCE1DDB43B6887C93580F8BAED5B5236EC69A7D1C42CCE978A98160AC51010001; //set private Key RSA CRT-2048 8034C100C8E7F037F8E89DF110BA672C16BDE2930EA223E2CF63FC030650DCA03289DD4FBE1056975FCB4566822E18C9A22437FA8685C7978187E1A72860E4BE19BEAA4A88A9C1A64F3186E39E6618039418528006281ADD687842CF8D27198C6D1E16166A4CE5A983263A776A5DCA829FC2F76B1A9369F5B5B2A62382593E8E00B3D36795C183B0BEB5D5171EC3DC28BD4BFE637F76AB6874EB6E7BCDAC5F782C7FD38C3A71394FA503DA1519413D60577AD831257E8C77356952B9F1BDF909FADC609F05002A532D6FFBEBAD; 8034C101C84E68A2FF5914E2A331CFC001586F74ACE4FFD23C2FB584B175070E2C3AC414259DC831536116BA669DB636FA82E65CE1C2D873E2B40552CDCAEDFEE1BCFBF77E31D1F82908A8B54CE471F58FF3B0B79EB00DE1D195033D52EA0DA48401961227A4D48E488081701DF08997D4C29BEAD4BF2F3BD1AB9431AA9775ED5A63958984BA30868AAE23BD2BBB1815764F5896BFD5AEC2FF2B08D23A7EC18D358C3D2E99798E0C9DABDD145A3F7E7FC741097762853E882DFCFEF0165153C60C9D646456FD45980C11611537; 8034C102C8985B04F8BB926E6D14858816B088CDA15391495AE9A7D81DE594037FBB3B75B91DC7B2B454B5272BDD6DD7CAA73487160C903E849E55321324B15EEFDAE772C4B5E355A78023CD2B2D7EA3E2CF1DE7963688813BDF77B8CFAF3B873A05DF43CAF9CDB9BE9079F91187C18B816B8CC151720904B29DBC80EF6443ECCE00665C83D48E95F3B0795F0388BC89B8CF6AFE8BC2051FE6022B159BD8522EDFDE48604DD4113A7E831E78ECF82235BB5AFAA53AF129FFF21AB7BDDE57025A6B57377386EFE7992231D71C4E; 803441032876743A93B519A6A45C6E57EFC081A3CDB6F92DF81092B02DA06AAC635B981CCBFD62488823C5AF51; //sign RSA CRT-2048 80358000C8111111413B40AD9D363E2A8192986A4F054C1C4BE30D47EDD76A32D1AA7EE9A9F91E5BA81D20819B5A5293D8C39F8549E3695E13BE12B19405110D2FBED0E393016D231B4201408CDE963377F802579313ECBBB49320B09D8216374EC50A70D70AE1DE5E0E05AD1B7A1F57638674309FB544EB35CBB5535D3C4C727FF633C6CFFF44F0E141B38074B5C92EF26A57B173F3DDE85C5D4F0B2A3F06E4F1961BB07712D9D0B901EDC8CEA67AEDDBBA0C7EA08857B6934168AF893E7F419DE51E45EEF8272274D85F89D8; //expect: 7008B8ACE976C4024F5148DCCF30DE9CEF6D330FE803B8516A8099CF795C9C57EF9092F1BA7CB75018BF0A7378062FC6D23208CE916F55E0BA471A977CE86FB3E6AAD1282E33E8E5B8FCCF31B2FF689127C292F9B8CC0F07DDDA17A4B870510F6E19187184C3749D1CA957AB2CDE752D459C3D9427A16168BDF1705536E87A97FAAEC1485F90857A0EB2A8DAF5EEDD59F8285D2E65B8D4DEB24EE59A72645B263D02D604EEE03F93EC04EDC8CBC08619E863B2C4A521244A101C6D2EA3E789F1616CE2DFA11190A6C928C0BE4117DF4555DEA280645454CFD755C3B547813FC46667C96223EC5458A9FCB51BBF9524183F0CF3A00A89B812F597CC7285573E7D9000 803500013895E867318D75FADC8AA35FC053B3E02EABA50B2D7B61F0F3EB7A4BCE1DDB43B6887C93580F8BAED5B5236EC69A7D1C42CCE978A98160AC51; //verify RSA CRT-2048 80368000C87008B8ACE976C4024F5148DCCF30DE9CEF6D330FE803B8516A8099CF795C9C57EF9092F1BA7CB75018BF0A7378062FC6D23208CE916F55E0BA471A977CE86FB3E6AAD1282E33E8E5B8FCCF31B2FF689127C292F9B8CC0F07DDDA17A4B870510F6E19187184C3749D1CA957AB2CDE752D459C3D9427A16168BDF1705536E87A97FAAEC1485F90857A0EB2A8DAF5EEDD59F8285D2E65B8D4DEB24EE59A72645B263D02D604EEE03F93EC04EDC8CBC08619E863B2C4A521244A101C6D2EA3E789F1616CE2DFA11190A6; 80368001C8C928C0BE4117DF4555DEA280645454CFD755C3B547813FC46667C96223EC5458A9FCB51BBF9524183F0CF3A00A89B812F597CC7285573E7D111111413B40AD9D363E2A8192986A4F054C1C4BE30D47EDD76A32D1AA7EE9A9F91E5BA81D20819B5A5293D8C39F8549E3695E13BE12B19405110D2FBED0E393016D231B4201408CDE963377F802579313ECBBB49320B09D8216374EC50A70D70AE1DE5E0E05AD1B7A1F57638674309FB544EB35CBB5535D3C4C727FF633C6CFFF44F0E141B38074B5C92EF26A57B173; //expect:01 90 00 8036000270F3DDE85C5D4F0B2A3F06E4F1961BB07712D9D0B901EDC8CEA67AEDDBBA0C7EA08857B6934168AF893E7F419DE51E45EEF8272274D85F89D895E867318D75FADC8AA35FC053B3E02EABA50B2D7B61F0F3EB7A4BCE1DDB43B6887C93580F8BAED5B5236EC69A7D1C42CCE978A98160AC51; //encrypt RSA CRT-2048 8037C800C8111111413B40AD9D363E2A8192986A4F054C1C4BE30D47EDD76A32D1AA7EE9A9F91E5BA81D20819B5A5293D8C39F8549E3695E13BE12B19405110D2FBED0E393016D231B4201408CDE963377F802579313ECBBB49320B09D8216374EC50A70D70AE1DE5E0E05AD1B7A1F57638674309FB544EB35CBB5535D3C4C727FF633C6CFFF44F0E141B38074B5C92EF26A57B173F3DDE85C5D4F0B2A3F06E4F1961BB07712D9D0B901EDC8CEA67AEDDBBA0C7EA08857B6934168AF893E7F419DE51E45EEF8272274D85F89D8; //expect:45ACD17EE02228DE45096F1153EF89DBF72933925A17803142A093FD2300CE27CF26A1B38F402E167647035227E0CBB238208A7E166E9DD4F563E04D48C9916C6812AA40AF4715C2D70D32190BC4F9EC2DA0FAD7EFE703AE2808401AA389698BC7428E9172B868E328DA5698CACDBE489EA871225DBEBB238B015828E4B68B274175910D1F72D8D684D24A40077F3A5C75F086A57B733C74CC94C7377A8F555DCB638A4A336344D9B2D53594E7C24BF3FA85705C2E6818B9703EDBBEFDCFA2FC42D3791816025BE4D3045ABF37AEEDF290B90D93E151AFA128E50A271A19AAA7988EBBACF17D26AAF8AAEA0C027186E2715E3A850971F5F16E44DB4FFACE07D09000 803748013895E867318D75FADC8AA35FC053B3E02EABA50B2D7B61F0F3EB7A4BCE1DDB43B6887C93580F8BAED5B5236EC69A7D1C42CCE978A98160AC51; //decrypt RSA CRT-2048 8037C900C845ACD17EE02228DE45096F1153EF89DBF72933925A17803142A093FD2300CE27CF26A1B38F402E167647035227E0CBB238208A7E166E9DD4F563E04D48C9916C6812AA40AF4715C2D70D32190BC4F9EC2DA0FAD7EFE703AE2808401AA389698BC7428E9172B868E328DA5698CACDBE489EA871225DBEBB238B015828E4B68B274175910D1F72D8D684D24A40077F3A5C75F086A57B733C74CC94C7377A8F555DCB638A4A336344D9B2D53594E7C24BF3FA85705C2E6818B9703EDBBEFDCFA2FC42D3791816025BE4; //expect:111111413B40AD9D363E2A8192986A4F054C1C4BE30D47EDD76A32D1AA7EE9A9F91E5BA81D20819B5A5293D8C39F8549E3695E13BE12B19405110D2FBED0E393016D231B4201408CDE963377F802579313ECBBB49320B09D8216374EC50A70D70AE1DE5E0E05AD1B7A1F57638674309FB544EB35CBB5535D3C4C727FF633C6CFFF44F0E141B38074B5C92EF26A57B173F3DDE85C5D4F0B2A3F06E4F1961BB07712D9D0B901EDC8CEA67AEDDBBA0C7EA08857B6934168AF893E7F419DE51E45EEF8272274D85F89D895E867318D75FADC8AA35FC053B3E02EABA50B2D7B61F0F3EB7A4BCE1DDB43B6887C93580F8BAED5B5236EC69A7D1C42CCE978A98160AC519000 8037490138D3045ABF37AEEDF290B90D93E151AFA128E50A271A19AAA7988EBBACF17D26AAF8AAEA0C027186E2715E3A850971F5F16E44DB4FFACE07D0;