forsyth20121205-174063a80cc13 years agoHistory
572 lines · 13.0 KB · Brainfuck
RawDownload
implement PKCS; include "sys.m";	sys				: Sys; include "keyring.m";	keyring				: Keyring;	IPint				: import keyring;	DESstate			: import keyring; include "security.m";	random				: Random; include "asn1.m";	asn1				: ASN1;	Elem, Oid			: import asn1; include "pkcs.m"; # pkcs object identifiers objIdTab = array [] of {	id_pkcs =>			Oid(array [] of {1,2,840,113549,1}),	id_pkcs_1 =>			Oid(array [] of {1,2,840,113549,1,1}),	id_pkcs_rsaEncryption => 	Oid(array [] of {1,2,840,113549,1,1,1}),	id_pkcs_md2WithRSAEncryption => Oid(array [] of {1,2,840,113549,1,1,2}),	id_pkcs_md4WithRSAEncryption => Oid(array [] of {1,2,840,113549,1,1,3}),	id_pkcs_md5WithRSAEncryption =>	Oid(array [] of {1,2,840,113549,1,1,4}), 	id_pkcs_3 =>			Oid(array [] of {1,2,840,113549,1,3}),	id_pkcs_dhKeyAgreement =>	Oid(array [] of {1,2,840,113549,1,3,1}), 	id_pkcs_5 =>			Oid(array [] of {1,2,840,113549,1,5}),	id_pkcs_pbeWithMD2AndDESCBC => 	Oid(array [] of {1,2,840,113549,1,5,1}),	id_pkcs_pbeWithMD5AndDESCBC =>	Oid(array [] of {1,2,840,113549,1,5,3}), 	id_pkcs_7 =>			Oid(array [] of {1,2,840,113549,1,7}),	id_pkcs_data =>			Oid(array [] of {1,2,840,113549,1,7,1}),	id_pkcs_singnedData => 		Oid(array [] of {1,2,840,113549,1,7,2}),	id_pkcs_envelopedData =>	Oid(array [] of {1,2,840,113549,1,7,3}),	id_pkcs_signedAndEnvelopedData => 						Oid(array [] of {1,2,840,113549,1,7,4}),	id_pkcs_digestData =>		Oid(array [] of {1,2,840,113549,1,7,5}),	id_pkcs_encryptedData =>	Oid(array [] of {1,2,840,113549,1,7,6}), 	id_pkcs_9 =>			Oid(array [] of {1,2,840,113549,1,9}),	id_pkcs_emailAddress => 	Oid(array [] of {1,2,840,113549,1,9,1}),	id_pkcs_unstructuredName =>	Oid(array [] of {1,2,840,113549,1,9,2}),	id_pkcs_contentType =>		Oid(array [] of {1,2,840,113549,1,9,3}),	id_pkcs_messageDigest =>	Oid(array [] of {1,2,840,113549,1,9,4}),	id_pkcs_signingTime =>		Oid(array [] of {1,2,840,113549,1,9,5}),	id_pkcs_countersignature =>	Oid(array [] of {1,2,840,113549,1,9,6}),	id_pkcs_challengePassword =>	Oid(array [] of {1,2,840,113549,1,9,7}),	id_pkcs_unstructuredAddress =>	Oid(array [] of {1,2,840,113549,1,9,8}),	id_pkcs_extCertAttrs =>		Oid(array [] of {1,2,840,113549,1,9,9}),	id_algorithm_shaWithDSS =>	Oid(array [] of {1,3,14,3,2,13})}; # [public]# initialize PKCS module init(): string{	sys = load Sys Sys->PATH;	if(sys == nil)		return "load sys module failed"; 	keyring = load Keyring Keyring->PATH;	if(keyring == nil)		return "load keyring module failed"; 	random = load Random Random->PATH;	if(random == nil)		return "load random module failed"; 	asn1 = load ASN1 ASN1->PATH;	if(asn1 == nil)		return "load asn1 module failed";	asn1->init(); 	return "";} # [public]# Encrypt data according to PKCS#1, with given blocktype, using given key. rsa_encrypt(data: array of byte, key: ref RSAKey, blocktype: int)	: (string, array of byte){	if(key == nil) 		return ("null pkcs#1 key", nil);	k := key.modlen;	dlen := len data;	if(k < 12 || dlen > k-11)		return ("bad parameters for pkcs#1", nil);	padlen := k-3-dlen;	pad := random->randombuf(Random->NotQuiteRandom, padlen);	for(i:=0; i < padlen; i++) {		if(blocktype == 0)			pad[i] = byte 0;		else if(blocktype == 1)			pad[i] = byte 16rff;		else if(pad[i] == byte 0)			pad[i] = byte 1;	}	eb := array[k] of byte;	eb[0] = byte 0;	eb[1] = byte blocktype;	eb[2:] = pad[0:];	eb[padlen+2] = byte 0;	eb[padlen+3:] = data[0:];	return ("", rsacomp(eb, key));} # [public]# Decrypt data according to PKCS#1, with given key.# If public is true, expect a block type of 0 or 1, else 2. rsa_decrypt(data: array of byte, key: ref RSAKey, public: int) 	: (string, array of byte){	eb := rsacomp(data, key);	k := key.modlen;	if(len eb == k) {		bt := int eb[1];		if(int eb[0] == 0 && ((public && (bt == 0 || bt == 1)) || (!public && bt == 2))) {			for(i := 2; i < k; i++)				if(eb[i] == byte 0)					break;			if(i < k-1) {				ans := array[k-(i+1)] of byte;				ans[0:] = eb[i+1:];				return ("", ans);			}		}	}	return ("pkcs1 decryption error", nil);} # [private]# Do RSA computation on block according to key, and pad# result on left with zeros to make it key.modlen long. rsacomp(block: array of byte, key: ref RSAKey): array of byte{	x := keyring->IPint.bebytestoip(block);	y := x.expmod(key.exponent, key.modulus);	ybytes := y.iptobebytes();	k := key.modlen;	ylen := len ybytes;	if(ylen < k) {		a := array[k] of { * =>  byte 0};		a[k-ylen:] = ybytes[0:];		ybytes = a;	}	else if(ylen > k) {		# assume it has leading zeros (mod should make it so)		a := array[k] of byte;		a[0:] = ybytes[ylen-k:];		ybytes = a;	}	return ybytes;} # [public] rsa_sign(data: array of byte, sk: ref RSAKey, algid: int): (string, array of byte){	# digesting and add proper padding to it	ph := padhash(data, algid); 	return rsa_encrypt(ph, sk, 0); # blocktype <- padding with zero} # [public] rsa_verify(data, signature: array of byte, pk: ref RSAKey, algid: int): int{	# digesting and add proper padding to it	ph := padhash(data, algid);    	(err, orig) := rsa_decrypt(signature, pk, 0); # blocktype ?	if(err != "" || !byte_cmp(orig, ph))		return 0; 	return 1;} # [private]# padding block APA := array [] of {	byte 16r30, byte 16r20, byte 16r30, byte 16r0c, 	byte 16r06, byte 16r08, byte 16r2a, byte 16r86, 	byte 16r48, byte 16r86, byte 16rf7, byte 16r0d, 	byte 16r02}; # [private]# padding block BPB := array [] of {byte 16r05, byte 16r00, byte 16r04, byte 16r10}; # [private]# require either md5 or md2 of 16 bytes digest# length of padded digest = 13 + 1 + 4 + 16 padhash(data: array of byte, algid: int): array of byte{	padded := array [34] of byte;	case algid {	MD2_WithRSAEncryption =>		padded[13] = byte 2;		# TODO: implement md2 in keyring module		# keyring->md2(data, len data, padded[18:], nil); 	MD5_WithRSAEncryption =>			padded[13] = byte 5;		keyring->md5(data, len data, padded[18:], nil);	* =>		return nil;	}	padded[0:] = PA;	padded[14:] = PB; 	return padded;} # [private]# compare byte to byte of two array of byte byte_cmp(a, b: array of byte): int{	if(len a != len b)		return 0; 	for(i := 0; i < len a; i++) {		if(a[i] != b[i])			return 0;	} 	return 1;} # [public] RSAKey.bits(key: self ref RSAKey): int{	return key.modulus.bits();} # [public]# Decode an RSAPublicKey ASN1 type, defined as:##	RSAPublickKey :: SEQUENCE {#		modulus INTEGER,#		publicExponent INTEGER#	} decode_rsapubkey(a: array of byte): (string, ref RSAKey){parse:	for(;;) {		(err, e) := asn1->decode(a);		if(err != "")			break parse;		(ok, el) := e.is_seq();		if(!ok || len el != 2)			break parse;		modbytes, expbytes: array of byte;		(ok, modbytes) = (hd el).is_bigint();		if(!ok)			break parse;		modulus := IPint.bebytestoip(modbytes);		# get modlen this way, because sometimes it		# comes with leading zeros that are to be ignored!		mbytes := modulus.iptobebytes();		modlen := len mbytes;		(ok, expbytes) = (hd tl el).is_bigint();		if(!ok)			break parse;		exponent := keyring->IPint.bebytestoip(expbytes);		return ("", ref RSAKey(modulus, modlen, exponent));	}	return ("rsa public key: syntax error", nil);}  # [public]# generate a pair of DSS public and private keys generateDSSKeyPair(strength: int): (ref DSSPublicKey, ref DSSPrivateKey){	# TODO: need add getRandBetween in IPint	return (nil, nil);} # [public] dss_sign(a: array of byte, sk: ref DSSPrivateKey): (string, array of byte){	#signature, digest: array of byte; 	#case hash {	#Keyring->MD4 =>	#	digest = array [Keyring->MD4dlen] of byte;	#	keyring->md4(a, len a, digest, nil);	#Keyring->MD5 =>	#	digest = array [Keyring->MD5dlen] of byte;	#	keyring->md5(a, len a, digest, nil);	#Keyring->SHA =>	#	digest = array [Keyring->SHA1dlen] of byte;	#	keyring->sha1(a, len a, digest, nil);	#* =>	#	return ("unknown hash algorithm", nil);	#} 	# TODO: add gcd or getRandBetween in Keyring->IPint	return ("unsupported error", nil);} # [public] dss_verify(a, signa: array of byte, pk: ref DSSPublicKey): int{	unsigned: array of byte; 	#case hash {	#Keyring->MD4 =>	#	digest = array [Keyring->MD4dlen] of byte;	#	keyring->md4(a, len a, digest, nil);	#Keyring->MD5 =>	#	digest = array [Keyring->MD5dlen] of byte;	#	keyring->md5(a, len a, digest, nil);	#Keyring->SHA =>	#	digest = array [Keyring->SHA1dlen] of byte;	#	keyring->sha1(a, len a, digest, nil);	#* =>	#	return 0;	#} 	# get unsigned from signa and compare it with digest 	if(byte_cmp(unsigned, a))		return 1; 	return 0;} # [public]decode_dsspubkey(a: array of byte): (string, ref DSSPublicKey){	return ("unsupported error", nil);}  # [public]# generate DH parameters with prime length at least (default) 512 bits generateDHParams(primelen: int): ref DHParams{	# prime - at least 512 bits	if(primelen < 512) # DHmodlen		primelen = 512; 	# generate prime and base (generator) integers	(p, g) := keyring->dhparams(primelen);	if(p == nil || g == nil)		return nil; 	return ref DHParams(p, g, 0);} # [public]# generate public and private key pair# Note: use iptobytes as integer to octet string conversion#	and bytestoip as octect string to integer reversion setupDHAgreement(dh: ref DHParams): (ref DHPrivateKey, ref DHPublicKey){	if(dh == nil || dh.prime == nil || dh.base == nil)		return (nil, nil); 	# prime length in bits	bits := dh.prime.bits(); 	# generate random private key of length between bits/4 and bits	x := IPint.random(bits/4, bits);	if(x == nil)		return (nil, nil);	dh.privateValueLength = x.bits(); 	# calculate public key	y := dh.base.expmod(x, dh.prime);	if(y == nil)		return (nil, nil); 	return (ref DHPrivateKey(dh, y, x), ref DHPublicKey(dh, x));} # [public]# The second phase of Diffie-Hellman key agreement computeDHAgreedKey(dh: ref DHParams, mysk, upk: ref IPint)	: array of byte{	if(mysk == nil || upk == nil)		return nil; 	# exponential - calculate agreed key (shared secret)	z := upk.expmod(mysk, dh.prime); 	# integer to octet conversion	return z.iptobebytes();} # [public]# ASN1 encoding decode_dhpubkey(a: array of byte): (string, ref DHPublicKey){	return ("unsupported error", nil);}  # [public]# Digest the concatenation of password and salt with count iterations of# selected message-digest algorithm (either md2 or md5).# The first 8 bytes of the message digest become the DES key.# The last 8 bytes of the message digest become the initializing vector IV. generateDESKey(pw: array of byte, param: ref PBEParams, alg: int)	: (ref DESstate, array of byte, array of byte){	if(param.iterationCount < 1)		return (nil, nil, nil); 	# concanate password and salt	pwlen := len pw;	pslen := pwlen + len param.salt;	ps := array [pslen] of byte;	ps[0:] = pw;	ps[pwlen:] = param.salt;	key, iv: array of byte; 	# digest iterations	case alg {	PBE_MD2_DESCBC =>		ds : ref Keyring->DigestState = nil;		# TODO: implement md2 in keyring module		#result := array [Keyring->MD2dlen] of byte;		#for(i := 0; i < param.iterationCount; i++)		#	ds = keyring->md2(ps, pslen, nil, ds);			#keyring->md2(ps, pslen, result, ds);			#key = result[0:8];		#iv = result[8:]; 	PBE_MD5_DESCBC =>		ds: ref Keyring->DigestState = nil;		result := array [Keyring->MD5dlen] of byte;		for(i := 0; i < param.iterationCount; i++) 			ds = keyring->md5(ps, pslen, nil, ds);		keyring->md5(ps, pslen, result, ds);		key = result[0:8];		iv = result[8:]; 	* =>		return (nil, nil, nil);	} 	state := keyring->dessetup(key, iv); 	return (state, key, iv);} # [public]# The message M and a padding string PS shall be formatted into# an octet string EB# 	EB = M + PS# where#	PS = 1 if M mod 8 = 7;#	PS = 2 + 2 if M mod 8 = 6;#	...#	PS = 8 + 8 + 8 + 8 + 8 + 8 + 8 + 8 if M mod 8 = 0; pbe_encrypt(state: ref DESstate, m: array of byte): array of byte{	mlen := len m;	padvalue :=  mlen % 8;	pdlen := 8 - padvalue; 	eb := array [mlen + pdlen] of byte;	eb[0:] = m;	for(i := mlen; i < pdlen; i++)		eb[i] = byte padvalue; 	keyring->descbc(state, eb, len eb, Keyring->Encrypt); 	return eb;} # [public]

Lines 1–500 of 572.