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(24), 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 24:
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