+static void
+test_RSA_keygen(const char *name, br_rsa_keygen kg, br_rsa_compute_modulus cm,
+ br_rsa_compute_pubexp ce, br_rsa_compute_privexp cd,
+ br_rsa_public pub, br_rsa_pkcs1_sign sign, br_rsa_pkcs1_vrfy vrfy)
+{
+ br_hmac_drbg_context rng;
+ int i;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ br_hmac_drbg_init(&rng, &br_sha256_vtable, "seed for RSA keygen", 19);
+
+ for (i = 0; i <= 42; i ++) {
+ unsigned size;
+ uint32_t pubexp, z;
+ br_rsa_private_key sk;
+ br_rsa_public_key pk, pk2;
+ unsigned char kbuf_priv[BR_RSA_KBUF_PRIV_SIZE(2048)];
+ unsigned char kbuf_pub[BR_RSA_KBUF_PUB_SIZE(2048)];
+ unsigned char n2[256], d[256], msg1[256], msg2[256];
+ uint32_t mod[256];
+ uint32_t cc;
+ size_t u, v;
+ unsigned char sig[257], hv[32], hv2[sizeof hv];
+ unsigned mask1, mask2;
+ int j;
+
+ if (i <= 35) {
+ size = 1024 + i;
+ pubexp = 17;
+ } else if (i <= 40) {
+ size = 2048;
+ pubexp = (i << 1) - 69;
+ } else {
+ size = 2048;
+ pubexp = 0xFFFFFFFF;
+ }
+
+ if (!kg(&rng.vtable,
+ &sk, kbuf_priv, &pk, kbuf_pub, size, pubexp))
+ {
+ fprintf(stderr, "RSA key pair generation failure\n");
+ exit(EXIT_FAILURE);
+ }
+
+ z = pubexp;
+ for (u = pk.elen; u > 0; u --) {
+ if (pk.e[u - 1] != (z & 0xFF)) {
+ fprintf(stderr, "wrong public exponent\n");
+ exit(EXIT_FAILURE);
+ }
+ z >>= 8;
+ }
+ if (z != 0) {
+ fprintf(stderr, "truncated public exponent\n");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(mod, 0, sizeof mod);
+ for (u = 0; u < sk.plen; u ++) {
+ for (v = 0; v < sk.qlen; v ++) {
+ mod[u + v] += (uint32_t)sk.p[sk.plen - 1 - u]
+ * (uint32_t)sk.q[sk.qlen - 1 - v];
+ }
+ }
+ cc = 0;
+ for (u = 0; u < sk.plen + sk.qlen; u ++) {
+ mod[u] += cc;
+ cc = mod[u] >> 8;
+ mod[u] &= 0xFF;
+ }
+ for (u = 0; u < pk.nlen; u ++) {
+ if (mod[pk.nlen - 1 - u] != pk.n[u]) {
+ fprintf(stderr, "wrong modulus\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ if (sk.n_bitlen != size) {
+ fprintf(stderr, "wrong key size\n");
+ exit(EXIT_FAILURE);
+ }
+ if (pk.nlen != (size + 7) >> 3) {
+ fprintf(stderr, "wrong modulus size (bytes)\n");
+ exit(EXIT_FAILURE);
+ }
+ mask1 = 0x01 << ((size + 7) & 7);
+ mask2 = 0xFF & -mask1;
+ if ((pk.n[0] & mask2) != mask1) {
+ fprintf(stderr, "wrong modulus size (bits)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (cm(NULL, &sk) != pk.nlen) {
+ fprintf(stderr, "wrong recomputed modulus length\n");
+ exit(EXIT_FAILURE);
+ }
+ if (cm(n2, &sk) != pk.nlen || memcmp(pk.n, n2, pk.nlen) != 0) {
+ fprintf(stderr, "wrong recomputed modulus value\n");
+ exit(EXIT_FAILURE);
+ }
+
+ z = ce(&sk);
+ if (z != pubexp) {
+ fprintf(stderr,
+ "wrong recomputed pubexp: %lu (exp: %lu)\n",
+ (unsigned long)z, (unsigned long)pubexp);
+ exit(EXIT_FAILURE);
+ }
+
+ if (cd(NULL, &sk, pubexp) != pk.nlen) {
+ fprintf(stderr,
+ "wrong recomputed privexp length (1)\n");
+ exit(EXIT_FAILURE);
+ }
+ if (cd(d, &sk, pubexp) != pk.nlen) {
+ fprintf(stderr,
+ "wrong recomputed privexp length (2)\n");
+ exit(EXIT_FAILURE);
+ }
+ /*
+ * To check that the private exponent is correct, we make
+ * it into a _public_ key, and use the public-key operation
+ * to perform the modular exponentiation.
+ */
+ pk2 = pk;
+ pk2.e = d;
+ pk2.elen = pk.nlen;
+ rng.vtable->generate(&rng.vtable, msg1, pk.nlen);
+ msg1[0] = 0x00;
+ memcpy(msg2, msg1, pk.nlen);
+ if (!pub(msg2, pk.nlen, &pk2) || !pub(msg2, pk.nlen, &pk)) {
+ fprintf(stderr, "public-key operation error\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(msg1, msg2, pk.nlen) != 0) {
+ fprintf(stderr, "wrong recomputed privexp\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * We test the RSA operation over a some random messages.
+ */
+ for (j = 0; j < 20; j ++) {
+ rng.vtable->generate(&rng.vtable, hv, sizeof hv);
+ memset(sig, 0, sizeof sig);
+ sig[pk.nlen] = 0x00;
+ if (!sign(BR_HASH_OID_SHA256,
+ hv, sizeof hv, &sk, sig))
+ {
+ fprintf(stderr,
+ "signature error (%d)\n", j);
+ exit(EXIT_FAILURE);
+ }
+ if (sig[pk.nlen] != 0x00) {
+ fprintf(stderr,
+ "signature length error (%d)\n", j);
+ exit(EXIT_FAILURE);
+ }
+ if (!vrfy(sig, pk.nlen, BR_HASH_OID_SHA256, sizeof hv,
+ &pk, hv2))
+ {
+ fprintf(stderr,
+ "signature verif error (%d)\n", j);
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(hv, hv2, sizeof hv) != 0) {
+ fprintf(stderr,
+ "signature extract error (%d)\n", j);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+