diff --git a/lib/modules/Crypto/dsa.pike b/lib/modules/Crypto/dsa.pike new file mode 100644 index 0000000000000000000000000000000000000000..2e1b6f6848699b9e2527daf98f002826cb244727 --- /dev/null +++ b/lib/modules/Crypto/dsa.pike @@ -0,0 +1,122 @@ +/* dsa.pike + * + * The Digital Signature Algorithm (aka DSS, Digital Signature Standard). + */ + +#define bignum object(Gmp.mpz) + +bignum p; /* Modulo */ +bignum q; /* Group order */ +bignum g; /* Generator */ + +bignum y; /* Public key */ +bignum x; /* Private key */ + +object set_public_key(bignum p_, bignum q_, bignum g_, bignum y_) +{ + p = p_; q = q_; g = g_; y = y_; + return this_object(); +} + +object set_private_key(bignum secret) +{ + x = secret; + return this_object(); +} + +bignum hash2number(string digest) +{ + return Gmp.mpz(digest, 256) % q; +} + +bignum dsa_hash(string msg) +{ + return hash2number(Crypto.sha()->update(msg)->digest()); +} + +/* Generate a random number k, 0<k<q */ +bignum random_exponent(function random) +{ + return Gmp.mpz(random( (q->size() + 10 / 8)), 256) % (q - 1) + 1; +} + +array(bignum) raw_sign(bignum h, function random) +{ + bignum k = random_exponent(random); + + bignum r = g->powm(k, p) % q; + bignum s = (k->invert(q) * (h + x*r)) % q; + + return ({ r, s }); +} + +int raw_verify(bignum h, bignum r, bignum s) +{ + bignum w; + if (catch + { + w = s->invert(q); + }) + /* Non-invertible */ + return 0; + + /* The inner %q's are redundant, as g^q == y^q == 1 (mod p) */ + return r == (g->powm(w * h % q, p) * y->powm(w * r % q, p) % p) % q; +} + +string sign_rsaref(string msg, function random) +{ + [bignum r, bignum s] = raw_sign(dsa_hash(msg), random); + + return sprintf("%'\0'20s%'\0'20s", r->digits(256), s->digits(256)); +} + +int verify_rsaref(string msg, string s) +{ + if (strlen(s) != 40) + return 0; + + return raw_verify(dsa_hash(msg), + Gmp.mpz(s[..19], 256), + Gmp.mpz(s[20..], 256)); +} + +string sign_ssl(string msg, function random) +{ + return Standards.ASN1.Types.asn1_sequence( + Array.map(raw_sign(dsa_hash(msg), random), + Standards.ASN1.Types.asn1_integer))->get_der(); +} + +int verify_ssl(string msg, string s) +{ + object a = Standards.ASN1.Decode.simple_der_decode(s); + + if (!a + || (a->type_name != "SEQUENCE") + || (sizeof(a->elements) != 2) + || (sizeof(a->elements->type_name - ({ "INTEGER" })))) + return 0; + + return raw_verify(dsa_hash(msg), + a->elements[0]->value, + a->elements[1]->value); +} + +object set_public_test_key() +{ + return set_public_key(Gmp.mpz("cc61a8f5a4f94e31f5412d462791e7b493e8360a2ad6e5288e67a106927feb0b3338f2b9e3d19d0056127f6aa2062d48ae0f41185633a3fc1b22ee34a2161e5a1885d99be7ba5cfa09a0abc4becf8598ea4ec2c81316d9e2c6d28385a53f2e03", + 16), + Gmp.mpz("f50473f33754ac2173968f96b50c24eb7d0a472d", + 16), + Gmp.mpz("1209dae33ba50a8f9f6cb00d1b1274bf5cc94acdf3e8a78df7a13aca0640465fdf1bc3b66ae068ccd0845abdb73e622f90b633372c7fa439a65732e8cf88077c686cc679b1c463a979c02696f6d99af05eea07d974a5fc3da6fa34ff48b030b5", + 16), + Gmp.mpz("7008517ecec3974b0a8813e5a39252b6b0051442f460bef29b4eb5c7f2972ac5f805c5383b6edcaa72596d50995b1e40f76b9a0b89ab4fb08f0458c38f2485740de6959e260e12e3052e1e28275ab84fdf3c7e9d347cb772792d4d38abcd3cfc", + 16)); +} + +object set_private_test_key() +{ + return set_private_key(Gmp.mpz("403a09fa0820287c84f2e8459a1fccf4c48c32e1", + 16)); +}