hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

pkcs1.ha (4310B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use bufio;
      5 use crypto::math;
      6 use crypto::sha1;
      7 use crypto::sha256;
      8 use crypto::sha512;
      9 use errors;
     10 use hash;
     11 use io;
     12 
     13 // Supported hash algorithms for [[pkcs1_sign]] and [[pkcs1_verify]].
     14 export type pkcs1_hashalgo = enum {
     15 	SHA1,
     16 	// SHA224, We don't have this one yet
     17 	SHA256,
     18 	SHA384,
     19 	SHA512,
     20 	SHA512_224,
     21 	SHA512_256,
     22 };
     23 
     24 const OID_SHA1: [_]u8 = [
     25 	0x30,  0x21,  0x30,  0x09,  0x06,  0x05,  0x2b,  0x0e,  0x03,  0x02,
     26 	0x1a,  0x05,  0x00,  0x04,  0x14,
     27 ];
     28 
     29 const OID_SHA224: [_]u8 = [
     30 	0x30,  0x2d,  0x30,  0x0d,  0x06,  0x09,  0x60,  0x86,  0x48,  0x01,
     31 	0x65,  0x03,  0x04,  0x02,  0x04,  0x05,  0x00,  0x04,  0x1c,
     32 ];
     33 
     34 const OID_SHA256: [_]u8 = [
     35 	0x30,  0x31,  0x30,  0x0d,  0x06,  0x09,  0x60,  0x86,  0x48,  0x01,
     36 	0x65,  0x03,  0x04,  0x02,  0x01,  0x05,  0x00,  0x04,  0x20,
     37 ];
     38 
     39 const OID_SHA384: [_]u8 = [
     40 	0x30,  0x41,  0x30,  0x0d,  0x06,  0x09,  0x60,  0x86,  0x48,  0x01,
     41 	0x65,  0x03,  0x04,  0x02,  0x02,  0x05,  0x00,  0x04,  0x30,
     42 ];
     43 
     44 const OID_SHA512: [_]u8 = [
     45 	0x30,  0x51,  0x30,  0x0d,  0x06,  0x09,  0x60,  0x86,  0x48,  0x01,
     46 	0x65,  0x03,  0x04,  0x02,  0x03,  0x05,  0x00,  0x04,  0x40,
     47 ];
     48 
     49 const OID_SHA512_224: [_]u8 = [
     50 	0x30,  0x2d,  0x30,  0x0d,  0x06,  0x09,  0x60,  0x86,  0x48,  0x01,
     51 	0x65,  0x03,  0x04,  0x02,  0x05,  0x05,  0x00,  0x04,  0x1c,
     52 ];
     53 
     54 const OID_SHA512_256: [_]u8 = [
     55 	0x30,  0x31,  0x30,  0x0d,  0x06,  0x09,  0x60,  0x86,  0x48,  0x01,
     56 	0x65,  0x03,  0x04,  0x02,  0x06,  0x05,  0x00,  0x04,  0x20,
     57 ];
     58 
     59 // Required buffer size for [[pkcs1_verify]].
     60 export def PKCS1_VERIFYBUFSZ: size = PUBEXP_BUFSZ + (BITSZ / 8);
     61 
     62 // Verifies a PKCS#1 v1.5 signature given a public key 'pubkey', the message
     63 // hash 'msghash', the signature 'sig' and the hash algorithm 'algo'. 'algo'
     64 // must reflect the hash algorithm 'sig' was created with.
     65 //
     66 // A temporary buffer 'buf' of size [[PKCS1_VERIFYBUFSZ]] must be provided.
     67 export fn pkcs1_verify(
     68 	pubkey: []u8,
     69 	msghash: []u8,
     70 	sig: []u8,
     71 	algo: pkcs1_hashalgo,
     72 	buf: []u8
     73 ) (void | error) = {
     74 	let pub = pubkey_params(pubkey);
     75 
     76 	let actualsig = buf[..len(sig)];
     77 	let pubbuf = buf[len(sig)..];
     78 
     79 	actualsig[..] = sig[..];
     80 	match (pubexp(&pub, actualsig, pubbuf)) {
     81 	case let e: error =>
     82 		return e;
     83 	case void => void;
     84 	};
     85 
     86 	let expectedsig = pubbuf[..len(sig)];
     87 	pkcs1_sig_encode(expectedsig, msghash, algo)?;
     88 
     89 	if (math::eqslice(expectedsig, actualsig) == 0) {
     90 		return badsig;
     91 	};
     92 };
     93 
     94 // Required buffer size for [[pkcs1_sign]].
     95 export def PKCS1_SIGNBUFSZ: size = PRIVEXP_BUFSZ;
     96 
     97 // Signs a message hash 'msghash' using the PKCS#1 V1.5 signature scheme. The
     98 // signature will be written to 'sig' which must be in the the size of the
     99 // modulus n (see [[privkey_nsize]]). 'algo' defines the hash algorithm
    100 // 'msghash' was created with.
    101 //
    102 // A temporary buffer 'buf' of size [[PKCS1_SIGNBUFSZ]]  must be provided.
    103 export fn pkcs1_sign(
    104 	priv: []u8,
    105 	msghash: []u8,
    106 	sig: []u8,
    107 	algo: pkcs1_hashalgo,
    108 	buf: []u8
    109 ) (void | error) = {
    110 	let priv = privkey_params(priv);
    111 	pkcs1_sig_encode(sig, msghash, algo)?;
    112 	privexp(&priv, sig, buf)?;
    113 };
    114 
    115 // Returns hash id and hash size for given 'algo'.
    116 fn pkcs1_hashinfo(algo: pkcs1_hashalgo) (const []u8, size) = {
    117 	switch (algo) {
    118 	case pkcs1_hashalgo::SHA1 =>
    119 		return (OID_SHA1, sha1::SZ);
    120 	case pkcs1_hashalgo::SHA256 =>
    121 		return (OID_SHA256, sha256::SZ);
    122 	case pkcs1_hashalgo::SHA384 =>
    123 		return (OID_SHA384, sha512::SZ384);
    124 	case pkcs1_hashalgo::SHA512 =>
    125 		return (OID_SHA512, sha512::SZ);
    126 	case pkcs1_hashalgo::SHA512_224 =>
    127 		return (OID_SHA512_224, sha512::SZ224);
    128 	case pkcs1_hashalgo::SHA512_256 =>
    129 		return (OID_SHA512_256, sha512::SZ256);
    130 	case =>
    131 		abort("unreachable");
    132 	};
    133 };
    134 
    135 // Creates an unauthenticated signature of 'msg' and writes it into 'sig' using
    136 // given hash algorithm 'algo'.
    137 fn pkcs1_sig_encode(
    138 	sig: []u8,
    139 	msghash: []u8,
    140 	algo: pkcs1_hashalgo
    141 ) (void | error) = {
    142 	let (hid, hsz) = pkcs1_hashinfo(algo);
    143 	if (len(msghash) != hsz) {
    144 		return errors::invalid;
    145 	};
    146 
    147 	let tlen = len(hid) + hsz;
    148 	if (len(sig) < tlen + 11) {
    149 		return badsig;
    150 	};
    151 
    152 	const hsep = len(sig) - tlen - 1;
    153 
    154 	sig[..2] = [0x00, 0x01];
    155 	for (let i = 2z; i < hsep; i += 1) {
    156 		sig[i] = 0xff;
    157 	};
    158 	sig[hsep] = 0x00;
    159 	sig[hsep + 1..len(sig) - hsz] = hid[..];
    160 	sig[len(sig) - hsz..] = msghash[..];
    161 };