1 /** 2 * --------- 3 * |.##> <##.| Open Smart Card Development Platform (www.openscdp.org) 4 * |# #| 5 * |# #| Copyright (c) 1999-2015 CardContact Software & System Consulting 6 * |'##> <##'| Andreas Schwier, 32429 Minden, Germany (www.cardcontact.de) 7 * --------- 8 * 9 * This file is part of OpenSCDP. 10 * 11 * OpenSCDP is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License version 2 as 13 * published by the Free Software Foundation. 14 * 15 * OpenSCDP is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with OpenSCDP; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 * 24 * @fileoverview Basic helper functions to encode and decode PKCS#1 padding 25 */ 26 27 28 29 /** 30 * Empty constructor 31 */ 32 function PKCS1() { 33 } 34 35 if (typeof(exports) != "undefined") 36 exports.PKCS1 = PKCS1; 37 38 39 /** 40 * Mask Generation Function 1 41 * 42 * @param {Crypto} crypto instance providing hash 43 * @param {Number} hashalg Hash algorithm (one of Crypto.SHA_xxx) 44 * @param {ByteString} mgfSeed Seed byte string 45 * @param {Number} maskLen length of requested masked 46 * @type ByteString 47 * @return the generated mask 48 */ 49 PKCS1.MGF1 = function(crypto, hashalg, mgfSeed, maskLen) { 50 if ((maskLen < 0) || (maskLen > 256)) { 51 throw new Error("maskLen out of range"); 52 } 53 var t = new ByteString("", HEX); 54 55 var c = 0; 56 while (t.length < maskLen) { 57 t = t.concat(crypto.digest(hashalg, mgfSeed.concat(ByteString.valueOf(c, 4)))); 58 c++; 59 } 60 return t.left(maskLen); 61 } 62 63 64 65 /** 66 * EME-OAEP decoder as defined in PKCS#1 V2.1 chapter 7.1.2 67 * 68 * @param {Crypto} crypto instance providing hash function 69 * @param {ByteString} label additional label for encryption 70 * @param {Number} hashalg Hash algorithm (one of Crypto.SHA_xxx) 71 * @param {ByteString} em encoded messages after RSA decrypt 72 * @type ByteString 73 * @return null if padding error or recovered message 74 */ 75 PKCS1.decode_EME_OAEP = function(crypto, label, hashalg, em) { 76 if (!label) { 77 label = new ByteString("", HEX); 78 } 79 80 var lHash = crypto.digest(hashalg, label); 81 var hLen = lHash.length; 82 var y = em.byteAt(0); 83 var maskedSeed = em.bytes(1, hLen); 84 var maskedDB = em.bytes(1 + hLen); 85 86 var seedMask = PKCS1.MGF1(crypto, hashalg, maskedDB, hLen); 87 var seed = maskedSeed.xor(seedMask); 88 var dbMask = PKCS1.MGF1(crypto, hashalg, seed, em.length - hLen - 1); 89 var DB = maskedDB.xor(dbMask); 90 91 var c1 = y == 0; 92 var c2 = DB.left(hLen).equals(lHash); 93 var cnt = 0; 94 var i = hLen; 95 for (; (i < DB.length) && (DB.byteAt(i) != 0x01); i++) { 96 cnt += (DB.byteAt(i) == 0x00) ? 1 : 0; 97 } 98 99 var c3 = i < DB.length; 100 var c4 = cnt == (i - hLen); 101 102 if (!c1 || !c2 || !c3 || !c4) { 103 return null; 104 } 105 return DB.bytes(i + 1); 106 } 107 108 109 110 /** 111 * EME-PKCS1-v1_5 decoder as defined in PKCS#1 V2.1 chapter 7.2.2 112 * 113 * @param {ByteString} em encoded messages after RSA decrypt 114 * @type ByteString 115 * @return null if padding error or recovered message 116 */ 117 PKCS1.decode_EME_V15 = function(em) { 118 var c1 = em.byteAt(0) == 0; 119 var c2 = em.byteAt(1) == 2; 120 121 for (i = 2; (i < em.length) && (em.byteAt(i) != 0x00); i++); 122 123 var c3 = i < em.length; 124 125 if (!c1 || !c2 || !c3) { 126 return null; 127 } 128 return em.bytes(i + 1); 129 } 130 131 132 133 PKCS1.ALLFF = new ByteString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", HEX); 134 135 /** 136 * EMSA-PKCS-v1_5 encoder as defined in PKCS#1 V2.1 chapter 9.2 137 * 138 * This method uses the length of the hash to determine the hash algorithm, i.e. MD5(16), SHA-1(20), SHA-224(28), SHA-256(32), SHA-384(48) or SHA-512(64) 139 * 140 * @param {Number} keysize the key size in bits 141 * @param {ByteString} hash the hash value 142 * @type ByteString 143 * @return the encoded message 144 */ 145 PKCS1.encode_EMSA_V15 = function(keysize, hash) { 146 switch(hash.length) { 147 case 16: 148 var oid = new ByteString("id-md5", OID); 149 break; 150 case 20: 151 var oid = new ByteString("id-sha1", OID); 152 break; 153 case 28: 154 var oid = new ByteString("id-sha224", OID); 155 break; 156 case 32: 157 var oid = new ByteString("id-sha256", OID); 158 break; 159 case 48: 160 var oid = new ByteString("id-sha384", OID); 161 break; 162 case 64: 163 var oid = new ByteString("id-sha512", OID); 164 break; 165 default: 166 throw new GPError(module.id, GPError.INVALID_DATA, 0, "Invalid hash length"); 167 } 168 var di = new ASN1(ASN1.SEQUENCE, 169 new ASN1(ASN1.SEQUENCE, 170 new ASN1(ASN1.OBJECT_IDENTIFIER, oid), 171 new ASN1(ASN1.NULL, new ByteString("", HEX)) 172 ), 173 new ASN1(ASN1.OCTET_STRING, hash) 174 ); 175 176 var t = di.getBytes(); 177 var em = new ByteBuffer("0001", HEX); 178 var pslen = (keysize >> 3) - t.length - 3; 179 while (pslen > 0) { 180 var l = pslen > 256 ? 256 : pslen; 181 em.append(PKCS1.ALLFF.left(l)); 182 pslen -= l; 183 } 184 em.append(0x00); 185 em.append(t); 186 return em.toByteString(); 187 } 188