/* Initialize BSafe pubkey structure from a RSApub. */ static int rpubk_init(B_KEY_OBJ rpubk, RSApub const *pub, PGPMemoryMgrRef mgr) { A_RSA_KEY kdata; PGPByte *buf; PGPSize bufsize; int err; bufsize = bnBytes(&pub->n) + bnBytes(&pub->e); buf = PGPNewSecureData( mgr, bufsize, 0 ); kdata.modulus.data = buf; kdata.modulus.len = bnBytes(&pub->n); kdata.exponent.data = buf + kdata.modulus.len; kdata.exponent.len = bnBytes(&pub->e); bnExtractBigBytes (&pub->n, kdata.modulus.data, 0, kdata.modulus.len); bnExtractBigBytes (&pub->e, kdata.exponent.data, 0, kdata.exponent.len); err = B_SetKeyInfo (rpubk, KI_RSAPublic, (POINTER)&kdata); pgpAssert (err == 0); pgpClearMemory (buf, bufsize); PGPFreeData (buf); return err; }
/* * Turn a PGPPubKey into the algorithm-specific parts of a public key. * A public key's DSA-specific part is: * * 0 2+i MPI for prime * 2+i 2+t MPI for order * 4+i+t 2+u MPI for generator * 6+i+t+u 2+v MPI for public key * 8+i+t+u+v */ static size_t dsaPubBufferLength(PGPPubKey const *pubkey) { DSApub const *pub = (DSApub *)pubkey->priv; return 8 + bnBytes(&pub->p) + bnBytes(&pub->q) + bnBytes(&pub->g) + bnBytes(&pub->y); }
int32_t ZrtpDH::getPubKeySize() const { dhCtx* tmpCtx = static_cast<dhCtx*>(ctx); if (pkType == DH2K || pkType == DH3K) return bnBytes(&tmpCtx->pubKey); if (pkType == EC25 || pkType == EC38 || pkType == E414) return bnBytes(tmpCtx->curve.p) * 2; // *2 -> x and y coordinate if (pkType == E255) return bnBytes(tmpCtx->curve.p); return 0; }
static size_t dsaPubMaxsig(PGPPubKey const *pubkey, PGPPublicKeyMessageFormat format) { DSApub const *pub = (DSApub *)pubkey->priv; ASSERTDSA(pubkey->pkAlg); if (format == kPGPPublicKeyMessageFormat_PGP) return 2*( 2 + bnBytes(&pub->q) ); else if (format == kPGPPublicKeyMessageFormat_PKCS1 || format == kPGPPublicKeyMessageFormat_IKE) return 2*( bnBytes(&pub->q) ); else if (format == kPGPPublicKeyMessageFormat_X509) { /* SEQUENCE, length, INT, INT */ PGPUInt32 len; PGPUInt32 qbytes = bnBytes(&pub->q); len = 2*(pgpBnX509LenLen(qbytes+1) + 1 + qbytes+1); return 1 + pgpBnX509LenLen(len) + len; } pgpAssert(0); return 0; }
static size_t dsaSecMaxsig(PGPSecKey const *seckey, PGPPublicKeyMessageFormat format) { DSAsecPlus const *sec = (DSAsecPlus *)seckey->priv; ASSERTDSA(seckey->pkAlg); if (format == kPGPPublicKeyMessageFormat_PGP) return 2*( 2 + bnBytes(&sec->s.q) ); else if (format == kPGPPublicKeyMessageFormat_PKCS1 || format == kPGPPublicKeyMessageFormat_IKE) return 2*( bnBytes(&sec->s.q) ); else if (format == kPGPPublicKeyMessageFormat_X509) { /* SEQUENCE, length, INT, INT */ PGPUInt32 len; PGPUInt32 qbytes = bnBytes(&sec->s.q); len = 2*(pgpBnX509LenLen(qbytes+1) + 1 + qbytes+1); return 1 + pgpBnX509LenLen(len) + len; } pgpAssert(0); return 0; }
static int dsaSign(PGPSecKey *seckey, PGPHashVTBL const *h, PGPByte const *hash, PGPByte *sig, size_t *siglen, PGPRandomContext const *rc, PGPPublicKeyMessageFormat format) { #if PGP_SIGN_DISABLE /* [ */ (void)seckey; (void)h; (void)hash; (void)sig; (void)siglen; (void)rc; (void)format; return kPGPError_FeatureNotAvailable; #else /* PGP_SIGN_DISABLE */ /* ] [ */ DSAsecPlus *sec = (DSAsecPlus *)seckey->priv; BigNum r, s, bn, k; unsigned t; unsigned qbits; unsigned qbytes; int i; PGPRandomContext *rc2; PGPMemoryMgrRef mgr = NULL; mgr = PGPGetContextMemoryMgr( seckey->context ); (void)h; /* We don't need this argument, although other algorithms may... */ (void)format; ASSERTDSA(seckey->pkAlg); /* Allow generalizations of SHA as long as they are big enough */ #if 0 pgpAssert(h->algorithm == kPGPHashAlgorithm_SHA); #else pgpAssert(h->hashsize*8 >= bnBits(&sec->s.q)); /* Make sure that q is the right size of we are using regular SHA hash */ pgpAssert( ! (h->algorithm == kPGPHashAlgorithm_SHA && bnBits(&sec->s.q) != h->hashsize*8) ); #endif if (sec->locked) return kPGPError_KeyIsLocked; /* * DSA requires a secret k. This k is *very* important * to keep secret. Consider, the DSA signing equations are: * r = (g^k mod p) mod q, and * s = k^-1 * (H(m) + x*r) mod q, * so if you know k (and, the signature r, s and H), then * x = r^-1 * (k*s - H(m)) * If we ever pick two k values the same, then * r = (g^k mod p) mod q is the same for both signatures, and * s1 = k^-1 * (H1 + x * r) * s2 = k^-1 * (H2 + x * r) * k = (H1-H2) / (s1-s2) * and proceed from there. * * So we need to make *very* sure there's no problem. To make * sure, we add a layer on top of the passed-in RNG. We assume * the passed-in RNG is good enough to never repeat (not a * difficult task), and apply an additional X9.17 generator on * top of that, seeded with the secret x, which is destroyed * before leaving this function. * * In addition, we add entropy from the hash to the original RNG. * This will prevent us from using the same k value twice if the * messages are different. */ pgpRandomAddBytes(rc, hash, bnBytes(&sec->s.q)); rc2 = pgpRandomCreateX9_17( rc->context, kPGPCipherAlgorithm_CAST5, rc); if (!rc2) return kPGPError_OutOfMemory; pgpRandomBnSeed(rc2, &sec->s.x); /* * Of these values, only k is inherently sensitive, but others may * hold some intermediate results we would prefer not to have leaked. * So mark all as sensitive. */ bnBegin(&r, mgr, TRUE ); bnBegin(&s, mgr, TRUE ); bnBegin(&bn, mgr, TRUE ); bnBegin(&k, mgr, TRUE ); /* * Choose the random k value to be used for this signature. * Make it a bit bigger than q so it is fairly uniform mod q. */ qbits = bnBits(&sec->s.q); qbytes = bnBytes(&sec->s.q); if (pgpBnGenRand(&k, rc2, qbits+8, 0, 1, qbits) < 0 || bnMod(&k, &k, &sec->s.q) < 0) goto nomem; /* Raise g to k power mod p then mod q to get r */ if (bnExpMod(&r, &sec->s.g, &k, &sec->s.p) < 0 || bnMod(&r, &r, &sec->s.q) < 0) goto nomem; /* r*x mod q into s */ if (bnMul(&s, &r, &sec->s.x) < 0 || bnMod(&s, &s, &sec->s.q) < 0) goto nomem; /* Pack message hash M into buffer bn */ if (bnInsertBigBytes(&bn, hash, 0, bnBytes(&sec->s.q)) < 0) goto nomem; if (bnMod(&bn, &bn, &sec->s.q) < 0) goto nomem; /* Add into s */ if (bnAdd(&s, &bn) < 0 || bnMod(&s, &s, &sec->s.q) < 0) goto nomem; /* Divide by k, mod q (k inverse held in bn) */ if (bnInv(&bn, &k, &sec->s.q) < 0 || bnMul(&s, &s, &bn) < 0 || bnMod(&s, &s, &sec->s.q) < 0) goto nomem; /* That's it, now to pack r and then s into the buffer */ t = 0; if (format == kPGPPublicKeyMessageFormat_X509) { /* Put in SEQUENCE header for 509 sig data */ PGPUInt32 len_seq, lenlen_seq; /* Count size of sequence, counting a 0 byte if hi bit is set */ if (8*qbytes == bnBits(&r)) len_seq = pgpBnX509LenLen(qbytes+1) + 1 + qbytes+1; else len_seq = pgpBnX509LenLen(qbytes) + 1 + qbytes; if (8*qbytes == bnBits(&s)) len_seq += pgpBnX509LenLen(qbytes+1) + 1 + qbytes+1; else len_seq += pgpBnX509LenLen(qbytes) + 1 + qbytes; lenlen_seq = pgpBnX509LenLen(len_seq); sig[t++] = X509_TAG_SEQUENCE | X509_TAG_CONSTRUCTED; if (--lenlen_seq == 0) { sig[t++] = len_seq; } else { sig[t++] = 0x80 | lenlen_seq; len_seq <<= 8 * (4-lenlen_seq); while (lenlen_seq--) { sig[t++] = (PGPByte)(len_seq >> 24); len_seq <<= 8; } } }
/* * Return 1 if (sig,siglen) is a valid MPI which signs * hash, of type h. Verify that the type is SHA.1 and * the hash itself matches. */ static int dsaVerify(PGPPubKey const *pubkey, PGPByte const *sig, size_t siglen, PGPHashVTBL const *h, PGPByte const *hash, PGPPublicKeyMessageFormat format) { #if PGP_VERIFY_DISABLE /* [ */ (void)pubkey; (void)sig; (void)siglen; (void)h; (void)hash; (void)format; return kPGPError_FeatureNotAvailable; #else /* PGP_VERIFY_DISABLE */ /* ] [ */ DSApub const *pub = (DSApub *)pubkey->priv; BigNum r, s, w, u2; int i; unsigned qbytes; size_t off; PGPMemoryMgrRef mgr = PGPGetContextMemoryMgr( pubkey->context ); ASSERTDSA(pubkey->pkAlg); /* Hashsize must be at least as big as size of q for legal sig */ if (h->hashsize*8 < bnBits(&pub->q)) { return 0; } #if 0 /* Allow generalizations of SHA, as long as they are big enough */ if (h->algorithm != kPGPHashAlgorithm_SHA) return 0; /* No match for sure! */ #endif bnBegin(&r, mgr, FALSE ); bnBegin(&s, mgr, FALSE ); bnBegin(&w, mgr, FALSE ); bnBegin(&u2, mgr, FALSE ); qbytes = bnBytes(&pub->q); /* sig holds two values. Get first, r, from sig. */ off = 0; if (format == kPGPPublicKeyMessageFormat_X509) { /* Parse SEQUENCE header for 509 sig data */ PGPByte const *sigp = sig + off; PGPUInt32 len; if (pgpBnX509TagLen(&sigp, &len) != X509_TAG_SEQUENCE) { i = kPGPError_MalformedKeyComponent; goto done; } off += sigp - sig; if (len != siglen - off) { i = kPGPError_MalformedKeyComponent; goto done; } } i = pgpBnGetFormatted(&r, sig+off, siglen-off, qbytes, format); if (i <= 0) goto fail; /* Get 2nd value, s, from SIG */ off += i; i = pgpBnGetFormatted(&s, sig+off, siglen-off, qbytes, format); if (i <= 0) goto fail; off += i; if (off != siglen) { i = kPGPError_BadSignatureSize; goto done; } /* * Sanity-check r and s against the subprime q. Both should * be less than q. If not, the signature is clearly bad. */ if (bnCmp(&r, &pub->q) >= 0 || bnCmp(&s, &pub->q) >= 0) { i = 0; /* FAIL */ goto done; } /* Reconstruct hash as u2 */ if (bnInsertBigBytes(&u2, hash, 0, bnBytes(&pub->q)) < 0) goto nomem; /* * Calculate DSS check function.... * Given signature (r,s) and hash H (in bn), compute: * w = s^-1 mod q * u1 = H * w mod q * u2 = r * w mod q * v = g^u1 * y^u2 mod p * if v == r mod q, the signature checks. * * To save space, we put u1 into s, H into u2, and v into w. */ if (bnInv(&w, &s, &pub->q) < 0) goto nomem; if (bnMul(&s, &u2, &w) < 0 || bnMod(&s, &s, &pub->q) < 0) goto nomem; if (bnMul(&u2, &r, &w) < 0 || bnMod(&u2, &u2, &pub->q) < 0) goto nomem; /* Now for the expensive part... */ if (bnDoubleExpMod(&w, &pub->g, &s, &pub->y, &u2, &pub->p) < 0) goto nomem; if (bnMod(&w, &w, &pub->q) < 0) goto nomem; /* Compare result with r, should be equal */ i = bnCmp(&w, &r) == 0; goto done; fail: if (!i) i = kPGPError_BadSignatureSize; goto done; nomem: i = kPGPError_OutOfMemory; goto done; done: bnEnd(&u2); bnEnd(&w); bnEnd(&s); bnEnd(&r); return i; #endif /* PGP_VERIFY_DISABLE */ /* ] */ }
/* * Performs an RSA decryption. Returns a prefix of the unwrapped * data in the given buf. Returns the length of the untruncated * data, which may exceed "len". Returns <0 on error. */ int rsaPrivateDecrypt(PGPByte *outbuf, unsigned len, BigNum *bn, RSAsec const *sec) { unsigned bytes = bnBytes(&sec->n); PGPByte *buf = NULL; B_ALGORITHM_OBJ bobj = NULL; B_KEY_OBJ rprivk = NULL; unsigned int bufoutlen; PGPMemoryMgrRef mgr = bn->mgr; int err; buf = PGPNewSecureData (mgr, bytes, 0); if (buf == NULL) { err = kPGPError_OutOfMemory; goto error; } bnExtractBigBytes (bn, buf, 0, bytes); /* Initialize BSafe private key structure */ err = B_CreateAlgorithmObject (&bobj); CHKERR(err); err = B_SetAlgorithmInfo (bobj, AI_RSAPrivate, NULL); CHKERR(err); err = B_CreateKeyObject (&rprivk); CHKERR(err); err = rprivk_init(rprivk, sec, mgr); CHKERR(err); err = B_DecryptInit (bobj, rprivk, RSA_CHOOSER, (A_SURRENDER_CTX *)0); CHKERR(err); /* Do an RSA decryption to recover PKCS-1 padded key */ err = B_DecryptUpdate (bobj, buf, &bufoutlen, bytes, buf, bytes, (B_ALGORITHM_OBJ)NULL, (A_SURRENDER_CTX *)NULL); CHKERR(err); err = B_DecryptFinal (bobj, buf+bufoutlen, &bufoutlen, bytes-bufoutlen, (B_ALGORITHM_OBJ)NULL, (A_SURRENDER_CTX *)NULL); CHKERR(err); B_DestroyKeyObject (&rprivk); rprivk = NULL; B_DestroyAlgorithmObject (&bobj); bobj = NULL; /* Return to bn format */ bnSetQ (bn, 0); bnInsertBigBytes (bn, buf, 0, bytes); pgpClearMemory (buf, bytes); PGPFreeData (buf); buf = NULL; err = pgpPKCSUnpack(outbuf, len, bn, PKCS_PAD_ENCRYPTED, bytes); error: if (buf) { pgpClearMemory (buf, bytes); PGPFreeData (buf); } if (rprivk) B_DestroyKeyObject (&rprivk); if (bobj) B_DestroyAlgorithmObject (&bobj); return err; }
/* * Encrypt a buffer holding a session key with an RSA public key */ int rsaPublicEncrypt(BigNum *bn, PGPByte const *in, unsigned len, RSApub const *pub, PGPRandomContext const *rc) { unsigned bytes = bnBytes(&pub->n); PGPByte *buf = NULL; B_ALGORITHM_OBJ bobj = NULL; B_KEY_OBJ rpubk = NULL; unsigned int bufoutlen; PGPMemoryMgrRef mgr = bn->mgr; int err = 0; pgpPKCSPack(bn, in, len, PKCS_PAD_ENCRYPTED, bytes, rc); buf = PGPNewSecureData (mgr, bytes, 0); if (buf == NULL) { err = kPGPError_OutOfMemory; goto error; } bnExtractBigBytes (bn, buf, 0, bytes); bnSetQ (bn, 0); /* Initialize BSafe public key structure */ err = B_CreateAlgorithmObject (&bobj); CHKERR(err); err = B_SetAlgorithmInfo (bobj, AI_RSAPublic, NULL); CHKERR(err); err = B_CreateKeyObject (&rpubk); CHKERR(err); err = rpubk_init(rpubk, pub, mgr); CHKERR(err); err = B_EncryptInit (bobj, rpubk, RSA_CHOOSER, (A_SURRENDER_CTX *)0); CHKERR(err); /* Encrypt data */ err = B_EncryptUpdate (bobj, buf, &bufoutlen, bytes, buf, bytes, (B_ALGORITHM_OBJ)NULL, (A_SURRENDER_CTX *)NULL); CHKERR(err); err = B_EncryptFinal (bobj, buf+bufoutlen, &bufoutlen, bytes-bufoutlen, (B_ALGORITHM_OBJ)NULL, (A_SURRENDER_CTX *)NULL); CHKERR(err); B_DestroyKeyObject (&rpubk); rpubk = NULL; B_DestroyAlgorithmObject (&bobj); bobj = NULL; /* Return to bn format */ bnInsertBigBytes (bn, buf, 0, bytes); pgpClearMemory (buf, bytes); PGPFreeData (buf); buf = NULL; error: if (buf) { pgpClearMemory (buf, bytes); PGPFreeData (buf); } if (rpubk) B_DestroyKeyObject (&rpubk); if (bobj) B_DestroyAlgorithmObject (&bobj); return err; }
/* Initialize BSafe privkey structure from a RSAsec. */ static int rprivk_init(B_KEY_OBJ rprivk, RSAsec const *sec, PGPMemoryMgrRef mgr) { BigNum dmodp, dmodq, tmp; A_RSA_CRT_KEY kdata; PGPByte *buf; PGPSize bufsize; int err; /* Calculate d mod p-1 and d mod q-1 */ bnBegin(&dmodp, mgr, TRUE); bnBegin(&dmodq, mgr, TRUE); bnBegin(&tmp, mgr, TRUE); bnCopy(&tmp, &sec->p); bnSubQ(&tmp, 1); bnMod(&dmodp, &sec->d, &tmp); bnCopy(&tmp, &sec->q); bnSubQ(&tmp, 1); bnMod(&dmodq, &sec->d, &tmp); bufsize = bnBytes(&sec->n) + bnBytes(&sec->q) + bnBytes(&sec->p) + bnBytes(&dmodq) + bnBytes(&dmodp) + bnBytes(&sec->u); buf = PGPNewSecureData( mgr, bufsize, 0 ); kdata.modulus.data = buf; kdata.modulus.len = bnBytes(&sec->n); kdata.prime[0].data = kdata.modulus.data + kdata.modulus.len; kdata.prime[0].len = bnBytes(&sec->q); kdata.prime[1].data = kdata.prime[0].data + kdata.prime[0].len; kdata.prime[1].len = bnBytes(&sec->p); kdata.primeExponent[0].data = kdata.prime[1].data + kdata.prime[1].len; kdata.primeExponent[0].len = bnBytes(&dmodq); kdata.primeExponent[1].data = kdata.primeExponent[0].data + kdata.primeExponent[0].len; kdata.primeExponent[1].len = bnBytes(&dmodp); kdata.coefficient.data = kdata.primeExponent[1].data + kdata.primeExponent[1].len; kdata.coefficient.len = bnBytes(&sec->u); bnExtractBigBytes (&sec->n, kdata.modulus.data, 0, kdata.modulus.len); bnExtractBigBytes (&sec->q, kdata.prime[0].data, 0, kdata.prime[0].len); bnExtractBigBytes (&sec->p, kdata.prime[1].data, 0, kdata.prime[1].len); bnExtractBigBytes (&dmodq, kdata.primeExponent[0].data, 0, kdata.primeExponent[0].len); bnExtractBigBytes (&dmodp, kdata.primeExponent[1].data, 0, kdata.primeExponent[1].len); bnExtractBigBytes (&sec->u, kdata.coefficient.data, 0, kdata.coefficient.len); err = B_SetKeyInfo (rprivk, KI_RSA_CRT, (POINTER)&kdata); pgpAssert (err == 0); pgpClearMemory (buf, bufsize); PGPFreeData (buf); bnEnd(&dmodp); bnEnd(&dmodq); bnEnd(&tmp); return err; }