unsigned int OpenSSLCryptoBase64::encode(unsigned char * inData, unsigned int inLength, unsigned char * outData, unsigned int outLength) { int outLen; if (outLength + 24 < inLength) { throw XSECCryptoException(XSECCryptoException::MemoryError, "OpenSSL:Base64 - Output buffer not big enough for Base64 encode"); } EVP_EncodeUpdate(&m_ectx, outData, &outLen, inData, inLength); if (outLen > (int) outLength) { throw XSECCryptoException(XSECCryptoException::MemoryError, "OpenSSL:Base64 - Output buffer not big enough for Base64 encode and overflowed"); } return outLen; }
void NSSCryptoKeyRSA::loadParamsFromKey(void) { if (mp_pubkey == 0) return; mp_modulus = SECITEM_DupItem(&(mp_pubkey->u.rsa.modulus)); if (mp_modulus == 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Error during extracting modulus from public key"); } mp_exponent = SECITEM_DupItem(&(mp_pubkey->u.rsa.publicExponent)); if (mp_exponent == 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Error during extracting exponent from public key"); } }
XSECCryptoKey * NSSCryptoKeyRSA::clone() const { NSSCryptoKeyRSA * ret; XSECnew(ret, NSSCryptoKeyRSA(mp_pubkey, mp_privkey)); if (mp_pubkey != 0) { ret->mp_pubkey = SECKEY_CopyPublicKey(mp_pubkey); if (ret->mp_pubkey == 0) { throw XSECCryptoException(XSECCryptoException::MemoryError, "NSS:RSA Error attempting to clone (copy) public key"); } } if (mp_privkey != 0) { ret->mp_privkey = SECKEY_CopyPrivateKey(mp_privkey); if (ret->mp_privkey == 0) { throw XSECCryptoException(XSECCryptoException::MemoryError, "NSS:RSA Error attempting to clone (copy) private key"); } } // Clone modulus if (mp_modulus != 0) { ret->mp_modulus = SECITEM_DupItem(mp_modulus); if (ret->mp_modulus == 0) { throw XSECCryptoException(XSECCryptoException::MemoryError, "NSS:RSA Error attempting to clone (copy) modulus"); } } // Clone exponent if (mp_exponent != 0) { ret->mp_exponent = SECITEM_DupItem(mp_exponent); if (ret->mp_exponent == 0) { throw XSECCryptoException(XSECCryptoException::MemoryError, "NSS:RSA Error attempting to clone (copy) exponent"); } } return ret; }
void NSSCryptoKeyRSA::importKey(void) { if (mp_pubkey != 0 || mp_exponent == NULL || mp_modulus == NULL) return; PRArenaPool * arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if(arena == NULL) { throw XSECCryptoException(XSECCryptoException::GeneralError, "NSS:RSA Error attempting create new arena"); } mp_pubkey = (SECKEYPublicKey*)PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey)); if(mp_pubkey == NULL ) { PORT_FreeArena(arena, PR_FALSE); throw XSECCryptoException(XSECCryptoException::GeneralError, "NSS:RSA Error attempting create new arena"); } mp_pubkey->arena = arena; mp_pubkey->keyType = rsaKey; SECStatus s = SECITEM_CopyItem(arena, &(mp_pubkey->u.rsa.modulus), mp_modulus); if (s != SECSuccess) { PORT_FreeArena(arena, PR_FALSE); throw XSECCryptoException(XSECCryptoException::DSAError, "NSS:RSA Error attempting to import modulus"); } s = SECITEM_CopyItem(arena, &(mp_pubkey->u.rsa.publicExponent), mp_exponent); if (s != SECSuccess) { PORT_FreeArena(arena, PR_FALSE); throw XSECCryptoException(XSECCryptoException::DSAError, "NSS:RSA Error attempting to import exponent"); } }
BIGNUM * OpenSSLCryptoBase64::b642BN(char * b64in, unsigned int len) { if (len > 1024) return NULL; int bufLen; unsigned char buf[1024]; EVP_ENCODE_CTX m_dctx; EVP_DecodeInit(&m_dctx); int rc = EVP_DecodeUpdate(&m_dctx, buf, &bufLen, (unsigned char *) b64in, len); if (rc < 0) { throw XSECCryptoException(XSECCryptoException::Base64Error, "OpenSSL:Base64 - Error during Base64 Decode of BIGNUMS"); } int finalLen; EVP_DecodeFinal(&m_dctx, &buf[bufLen], &finalLen); bufLen += finalLen; // Now translate to a bignum return BN_dup(BN_bin2bn(buf, bufLen, NULL)); }
void WinCAPICryptoX509::loadX509Base64Bin(const char * buf, unsigned int len) { unsigned char * rawCert; XSECnew(rawCert, unsigned char [len]); ArrayJanitor<unsigned char> j_rawCert(rawCert); // Base64 Decode XSCryptCryptoBase64 b64; b64.decodeInit(); unsigned int rawCertLen = b64.decode((unsigned char *) buf, len, rawCert, len); rawCertLen += b64.decodeFinish(&rawCert[rawCertLen], len - rawCertLen); // Now load certificate into Win32 CSP mp_certContext = CertCreateCertificateContext( X509_ASN_ENCODING, rawCert, rawCertLen); if (mp_certContext == 0) { throw XSECCryptoException(XSECCryptoException::X509Error, "WinCAPIX509:loadX509Base64Bin - Error decoding certificate"); } m_DERX509.sbMemcpyIn(buf, len); m_DERX509[len] = '\0'; }
void NSSCryptoKeyRSA::setMGF(maskGenerationFunc mgf) { if (mgf != MGF1_SHA1) throw XSECCryptoException(XSECCryptoException::UnsupportedError, "NSS::setMGF - NSS does not support pluggable MGF for OAEP"); }
WinCAPICryptoHashHMAC::WinCAPICryptoHashHMAC(HCRYPTPROV prov, HashType alg) { m_p = prov; m_h = 0; m_blockSize = 64; // We only know SHA-1 and MD5 at this time - both are 64 bytes switch (alg) { case (XSECCryptoHash::HASH_SHA1) : m_algId = CALG_SHA; break; case (XSECCryptoHash::HASH_MD5) : m_algId = CALG_MD5; break; default : m_algId = 0; } if(m_algId == 0) { throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:Hash - Unknown algorithm"); } m_hashType = alg; }
WinCAPICryptoX509::WinCAPICryptoX509(PCCERT_CONTEXT pCertContext, HCRYPTPROV provRSA, HCRYPTPROV provDSS) : m_pRSA(provRSA), m_pDSS(provDSS) { // Build this from an existing PCCERT_CONTEXT structure mp_certContext = pCertContext; unsigned char * encCert; unsigned long len = mp_certContext->cbCertEncoded * 2; XSECnew(encCert, unsigned char [len]); ArrayJanitor<unsigned char> j_encCert(encCert); // Base64 Encode XSCryptCryptoBase64 b64; b64.encodeInit(); unsigned long encCertLen = b64.encode(mp_certContext->pbCertEncoded, mp_certContext->cbCertEncoded, encCert, len); encCertLen += b64.encodeFinish(&encCert[encCertLen], len - encCertLen); // Check the result if (encCert == NULL) { throw XSECCryptoException(XSECCryptoException::X509Error, "WinCAPIX509:WinCAPIX509 - Error encoding certificate"); } m_DERX509.sbMemcpyIn(encCert, encCertLen); m_DERX509[encCertLen] = '\0'; }
void OpenPGPCryptoHashHMAC::hash(unsigned char * data, unsigned int length) { if (!m_initialised) throw XSECCryptoException(XSECCryptoException::MDError, "OpenPGP:HashHMAC - hash called prior to setKey"); mp_md->update(std::string(reinterpret_cast<char *>(data), length)); }
void NSSCryptoKeyRSA::setOAEPparams(unsigned char * params, unsigned int paramsLen) { if (params != NULL && paramsLen != 0) { throw XSECCryptoException(XSECCryptoException::UnsupportedError, "NSS::setOAEPParams - OAEP parameters are not supported by NSS"); } }
void WinCAPICryptoHashHMAC::hash(unsigned char * data, unsigned int length) { if (m_h == 0) { throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:HashHMAC::hash() - Called prior to setting key"); } BOOL fResult = CryptHashData( m_h, data, length, 0); if (fResult == 0) { throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:Hash - Error Hashing Data"); } }
unsigned int OpenSSLCryptoBase64::decode(unsigned char * inData, unsigned int inLength, unsigned char * outData, unsigned int outLength) { int rc; int outLen; if (outLength < inLength) { throw XSECCryptoException(XSECCryptoException::MemoryError, "OpenSSL:Base64 - Output buffer not big enough for Base64 decode"); } rc = EVP_DecodeUpdate(&m_dctx, outData, &outLen, inData, inLength); if (rc < 0) { throw XSECCryptoException(XSECCryptoException::Base64Error, "OpenSSL:Base64 - Error during Base64 Decode"); } if (outLen > (int) outLength) { throw XSECCryptoException(XSECCryptoException::MemoryError, "OpenSSL:Base64 - Output buffer not big enough for Base64 decode and overflowed"); } return outLen; }
void OpenPGPCryptoHashHMAC::reset(void) { std::string key(m_keyBuf.rawBuffer(), m_keyLen); switch (m_hashType) { case (XSECCryptoHash::HASH_SHA1) : mp_md.reset(HMAC_SHA1(key)); break; case (XSECCryptoHash::HASH_MD5) : mp_md.reset(HMAC_MD5(key)); break; case (XSECCryptoHash::HASH_SHA224) : mp_md.reset(HMAC_SHA224(key)); break; case (XSECCryptoHash::HASH_SHA256) : mp_md.reset(HMAC_SHA256(key)); break; case (XSECCryptoHash::HASH_SHA384) : mp_md.reset(HMAC_SHA384(key)); break; case (XSECCryptoHash::HASH_SHA512) : mp_md.reset(HMAC_SHA512(key)); break; default : mp_md.reset(); } if(!mp_md) { throw XSECCryptoException(XSECCryptoException::MDError, "OpenPGP:HashHMAC - Error loading Message Digest"); } }
void OpenPGPCryptoHashHMAC::setKey(XSECCryptoKey *key) { // Use this to initialise the HMAC Context if (key->getKeyType() != XSECCryptoKey::KEY_HMAC) { throw XSECCryptoException(XSECCryptoException::MDError, "OpenPGP:HashHMAC - Non HMAC Key passed to OpenPGPHashHMAC"); } m_keyLen = ((XSECCryptoKeyHMAC *) key)->getKey(m_keyBuf); reset(); }
XSECCryptoKey::KeyType WinCAPICryptoX509::getPublicKeyType() const { if (mp_certContext == NULL) { throw XSECCryptoException(XSECCryptoException::X509Error, "WinCAPI:X509 - getPublicKeyType called before X509 loaded"); } if (lstrcmp(mp_certContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, CRYPTO_OID_DSA) == 0) return XSECCryptoKey::KEY_DSA_PUBLIC; if (lstrcmp(mp_certContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_RSA_RSA) == 0) return XSECCryptoKey::KEY_RSA_PUBLIC; return XSECCryptoKey::KEY_NONE; }
// Get functions XSECCryptoKey * WinCAPICryptoX509::clonePublicKey() const { if (mp_certContext == NULL) { throw XSECCryptoException(XSECCryptoException::X509Error, "WinCAPI:X509 - clonePublicKey called before X509 loaded"); } // Import the key into the provider to get a pointer to the key HCRYPTKEY key; BOOL fResult; if (getPublicKeyType() == XSECCryptoKey::KEY_DSA_PUBLIC) { fResult= CryptImportPublicKeyInfo( m_pDSS, X509_ASN_ENCODING, &(mp_certContext->pCertInfo->SubjectPublicKeyInfo), &key); if (fResult == FALSE) { throw XSECCryptoException(XSECCryptoException::X509Error, "WinCAPI:X509 - Error loading public key info from certificate"); } // Now that we have a handle for the DSA key, create a DSA Key object to // wrap it in WinCAPICryptoKeyDSA * ret; XSECnew(ret, WinCAPICryptoKeyDSA(m_pDSS, key)); return ret; } if (getPublicKeyType() == XSECCryptoKey::KEY_RSA_PUBLIC) { fResult= CryptImportPublicKeyInfo( m_pRSA, X509_ASN_ENCODING, &(mp_certContext->pCertInfo->SubjectPublicKeyInfo), &key); if (fResult == FALSE) { throw XSECCryptoException(XSECCryptoException::X509Error, "WinCAPI:X509 - Error loading public key info from certificate"); } // Now that we have a handle for the DSA key, create a DSA Key object to // wrap it in WinCAPICryptoKeyRSA * ret; XSECnew(ret, WinCAPICryptoKeyRSA(m_pRSA, key)); return ret; } return NULL; // Unknown key type, but not necessarily an error }
unsigned int OpenSSLCryptoKeyDSA::signBase64Signature(unsigned char * hashBuf, unsigned int hashLen, char * base64SignatureBuf, unsigned int base64SignatureBufLen) { // Sign a pre-calculated hash using this key if (mp_dsaKey == NULL) { throw XSECCryptoException(XSECCryptoException::DSAError, "OpenSSL:DSA - Attempt to sign data with empty key"); } DSA_SIG * dsa_sig; dsa_sig = DSA_do_sign(hashBuf, hashLen, mp_dsaKey); if (dsa_sig == NULL) { throw XSECCryptoException(XSECCryptoException::DSAError, "OpenSSL:DSA - Error signing data"); } // Now turn the signature into a base64 string unsigned char rawSigBuf[256]; unsigned int rawLen; rawLen = BN_bn2bin(dsa_sig->r, rawSigBuf); if (rawLen <= 0) { throw XSECCryptoException(XSECCryptoException::DSAError, "OpenSSL:DSA - Error converting signature to raw buffer"); } unsigned int rawLenS = BN_bn2bin(dsa_sig->s, (unsigned char *) &rawSigBuf[rawLen]); if (rawLenS <= 0) { throw XSECCryptoException(XSECCryptoException::DSAError, "OpenSSL:DSA - Error converting signature to raw buffer"); } rawLen += rawLenS; // Now convert to Base 64 BIO * b64 = BIO_new(BIO_f_base64()); BIO * bmem = BIO_new(BIO_s_mem()); BIO_set_mem_eof_return(bmem, 0); b64 = BIO_push(b64, bmem); // Translate signature from Base64 BIO_write(b64, rawSigBuf, rawLen); BIO_flush(b64); unsigned int sigValLen = BIO_read(bmem, base64SignatureBuf, base64SignatureBufLen); BIO_free_all(b64); if (sigValLen <= 0) { throw XSECCryptoException(XSECCryptoException::DSAError, "OpenSSL:DSA - Error base64 encoding signature"); } return sigValLen; }
unsigned int WinCAPICryptoHashHMAC::finish(unsigned char * hash, unsigned int maxLength) { DWORD retLen; BOOL fResult; retLen = XSEC_MAX_HASH_SIZE; fResult = CryptGetHashParam( m_h, HP_HASHVAL, m_mdValue, &retLen, 0); if (fResult == 0) { throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:Hash - Error getting hash value"); } // Perform the opad operation HCRYPTHASH h; fResult = CryptCreateHash( m_p, m_algId, 0, 0, &h); if (fResult == 0 || h == 0) { throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:Hash::finish - Error creating hash object for opad operation"); } fResult = CryptHashData( h, m_opadKeyed, m_blockSize, 0); if (fResult == 0 || h == 0) { if (h) CryptDestroyHash(h); throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:Hash::finish - Error hashing opad data"); } fResult = CryptHashData( h, m_mdValue, retLen, 0); if (fResult == 0 || h == 0) { if (h) CryptDestroyHash(h); throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:Hash::finish - Error hashing ipad hash to opad"); } // Read out the final hash retLen = XSEC_MAX_HASH_SIZE; fResult = CryptGetHashParam( h, HP_HASHVAL, m_mdValue, &retLen, 0); CryptDestroyHash(h); m_mdLen = retLen; retLen = (maxLength > m_mdLen ? m_mdLen : maxLength); memcpy(hash, m_mdValue, retLen); return (unsigned int) retLen; }
unsigned int OpenSSLCryptoKeyRSA::publicEncrypt(const unsigned char * inBuf, unsigned char * cipherBuf, unsigned int inLength, unsigned int maxOutLength, PaddingType padding, hashMethod hm) { // Perform an encrypt if (mp_rsaKey == NULL) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA - Attempt to encrypt data with empty key"); } int encryptSize; switch (padding) { case XSECCryptoKeyRSA::PAD_PKCS_1_5 : encryptSize = RSA_public_encrypt(inLength, #if defined(XSEC_OPENSSL_CONST_BUFFERS) inBuf, #else (unsigned char *) inBuf, #endif cipherBuf, mp_rsaKey, RSA_PKCS1_PADDING); if (encryptSize < 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA publicKeyEncrypt - Error performing PKCS1_5 padded RSA encrypt"); } break; case XSECCryptoKeyRSA::PAD_OAEP_MGFP1 : { unsigned char * tBuf; unsigned int num = RSA_size(mp_rsaKey); if (maxOutLength < num) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA publicKeyEncrypt - Not enough space in cipherBuf"); } const EVP_MD* evp_md = NULL; const EVP_MD* mgf_md = NULL; switch (hm) { case HASH_SHA1: evp_md = EVP_get_digestbyname("SHA1"); break; case HASH_SHA224: evp_md = EVP_get_digestbyname("SHA224"); break; case HASH_SHA256: evp_md = EVP_get_digestbyname("SHA256"); break; case HASH_SHA384: evp_md = EVP_get_digestbyname("SHA384"); break; case HASH_SHA512: evp_md = EVP_get_digestbyname("SHA512"); break; } if (evp_md == NULL) { throw XSECCryptoException(XSECCryptoException::MDError, "OpenSSL:RSA - OAEP digest algorithm not supported by this version of OpenSSL"); } switch (m_mgf) { case MGF1_SHA1: mgf_md = EVP_get_digestbyname("SHA1"); break; case MGF1_SHA224: mgf_md = EVP_get_digestbyname("SHA224"); break; case MGF1_SHA256: mgf_md = EVP_get_digestbyname("SHA256"); break; case MGF1_SHA384: mgf_md = EVP_get_digestbyname("SHA384"); break; case MGF1_SHA512: mgf_md = EVP_get_digestbyname("SHA512"); break; } if (mgf_md == NULL) { throw XSECCryptoException(XSECCryptoException::MDError, "OpenSSL:RSA - MGF not supported by this version of OpenSSL"); } XSECnew(tBuf, unsigned char[num]); ArrayJanitor<unsigned char> j_tBuf(tBuf); // First add the padding encryptSize = RSA_padding_add_PKCS1_OAEP(tBuf, num, //#if defined(XSEC_OPENSSL_CONST_BUFFERS) inBuf, //#else // (unsigned char *) inBuf, //#endif inLength, mp_oaepParams, m_oaepParamsLen, evp_md, mgf_md); if (encryptSize <= 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA publicKeyEncrypt - Error adding OAEPadding"); } encryptSize = RSA_public_encrypt(num, tBuf, cipherBuf, mp_rsaKey, RSA_NO_PADDING); if (encryptSize < 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA publicKeyEncrypt - Error encrypting padded data"); } } break; default : throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA - Unknown padding method"); } return encryptSize; }
void WinCAPICryptoHashHMAC::setKey(XSECCryptoKey *key) { BOOL fResult; // Use this to initialise the ipadKeyed/opadKeyed values if (key->getKeyType() != XSECCryptoKey::KEY_HMAC) { throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:HashHMAC - Non HMAC Key passed to HashHMAC"); } if (m_blockSize > XSEC_MAX_HASH_BLOCK_SIZE) { throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:HashHMAC - Internal error - have got a blocksize bigger than I can handle"); } // Check to see if this is an internal Windows Key if (strEquals(key->getProviderName(), DSIGConstants::s_unicodeStrPROVWinCAPI) && ((WinCAPICryptoKeyHMAC *) key)->getWinKey() != 0) { // Over-ride the local provider for this HCRYPTPROV p = ((WinCAPICryptoKeyHMAC *) key)->getWinKeyProv(); HCRYPTKEY k = ((WinCAPICryptoKeyHMAC *) key)->getWinKey(); fResult = CryptCreateHash( p, CALG_HMAC, k, 0, &m_h); if (fResult == 0 || m_h == 0) { DWORD error = GetLastError(); throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:Hash::setKey - Error creating internally keyed hash object"); } // Set the HMAC algorithm HMAC_INFO hi; hi.HashAlgid = m_algId; hi.pbInnerString = NULL; // Use default inner and outer strings hi.cbInnerString = 0; hi.pbOuterString = NULL; hi.cbOuterString = 0; fResult = CryptSetHashParam( m_h, HP_HMAC_INFO, (BYTE *) &hi, 0); if (fResult == 0 || m_h == 0) { DWORD error = GetLastError(); throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:Hash::setKey - Error setting HASH_INFO object"); } return; } // Need to load from raw bit string safeBuffer keyBuf; unsigned int keyLen = ((XSECCryptoKeyHMAC *) key)->getKey(keyBuf); if (keyLen > m_blockSize) { HCRYPTHASH h; fResult = CryptCreateHash( m_p, m_algId, 0, 0, &h); if (fResult == 0 || h == 0) { throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:Hash::setKey - Error creating hash object"); } fResult = CryptHashData( h, keyBuf.rawBuffer(), keyLen, 0); if (fResult == 0 || h == 0) { if (h) CryptDestroyHash(h); throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:Hash::setKey - Error hashing key data"); } BYTE outData[XSEC_MAX_HASH_SIZE]; DWORD outDataLen = XSEC_MAX_HASH_SIZE; CryptGetHashParam( h, HP_HASHVAL, outData, &outDataLen, 0); if (fResult == 0 || h == 0) { if (h) CryptDestroyHash(h); throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:Hash::setKey - Error getting hash result"); } keyBuf.sbMemcpyIn(outData, outDataLen); keyLen = outDataLen; if (h) CryptDestroyHash(h); } // Now create the ipad and opad keyed values memcpy(m_ipadKeyed, ipad, m_blockSize); memcpy(m_opadKeyed, opad, m_blockSize); // XOR with the key for (unsigned int i = 0; i < keyLen; ++i) { m_ipadKeyed[i] = keyBuf[i] ^ m_ipadKeyed[i]; m_opadKeyed[i] = keyBuf[i] ^ m_opadKeyed[i]; } // Now create the hash object, and start with the ipad operation fResult = CryptCreateHash( m_p, m_algId, 0, 0, &m_h); if (fResult == 0 || m_h == 0) { throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:HashHMAC - Error creating hash object"); } fResult = CryptHashData( m_h, m_ipadKeyed, m_blockSize, 0); if (fResult == 0 || m_h == 0) { throw XSECCryptoException(XSECCryptoException::MDError, "WinCAPI:HashHMAC - Error performing initial ipad digest"); } }
unsigned int OpenSSLCryptoKeyRSA::signSHA1PKCS1Base64Signature(unsigned char * hashBuf, unsigned int hashLen, char * base64SignatureBuf, unsigned int base64SignatureBufLen, hashMethod hm) { // Sign a pre-calculated hash using this key if (mp_rsaKey == NULL) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA - Attempt to sign data with empty key"); } // Build the buffer to be encrypted by prepending the SHA1 OID to the hash unsigned char * encryptBuf; unsigned char * preEncryptBuf; unsigned char * oid; int oidLen; int encryptLen; int preEncryptLen; oid = getRSASigOID(hm, oidLen); if (oid == NULL) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA::sign() - Unsupported HASH algorithm for RSA"); } if (hashLen != oid[oidLen-1]) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA::sign() - hashLen incorrect for hash type"); } preEncryptLen = hashLen + oidLen; preEncryptBuf = new unsigned char[preEncryptLen]; encryptBuf = new unsigned char[RSA_size(mp_rsaKey)]; memcpy(preEncryptBuf, oid, oidLen); memcpy(&preEncryptBuf[oidLen], hashBuf, hashLen); // Now encrypt encryptLen = RSA_private_encrypt(preEncryptLen, preEncryptBuf, encryptBuf, mp_rsaKey, RSA_PKCS1_PADDING); delete[] preEncryptBuf; if (encryptLen < 0) { delete[] encryptBuf; throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA::sign() - Error encrypting hash"); } // Now convert to Base 64 BIO * b64 = BIO_new(BIO_f_base64()); BIO * bmem = BIO_new(BIO_s_mem()); BIO_set_mem_eof_return(bmem, 0); b64 = BIO_push(b64, bmem); // Translate signature to Base64 BIO_write(b64, encryptBuf, encryptLen); BIO_flush(b64); unsigned int sigValLen = BIO_read(bmem, base64SignatureBuf, base64SignatureBufLen); BIO_free_all(b64); delete[] encryptBuf; if (sigValLen <= 0) { throw XSECCryptoException(XSECCryptoException::DSAError, "OpenSSL:RSA - Error base64 encoding signature"); } return sigValLen; }
unsigned int OpenSSLCryptoKeyRSA::privateDecrypt(const unsigned char * inBuf, unsigned char * plainBuf, unsigned int inLength, unsigned int maxOutLength, PaddingType padding, hashMethod hm) { // Perform a decrypt if (mp_rsaKey == NULL) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA - Attempt to decrypt data with empty key"); } #if 0 /* normally commented out code to determine endian problems */ unsigned int i; unsigned char e[2048]; unsigned char * inBuf1 = (unsigned char *) inBuf; if (inLength < 2048) { memcpy(e, inBuf, inLength); for (i = 0; i < inLength;++i) { inBuf1[i] = e[inLength - 1 - i]; } } #endif int decryptSize; switch (padding) { case XSECCryptoKeyRSA::PAD_PKCS_1_5 : decryptSize = RSA_private_decrypt(inLength, #if defined(XSEC_OPENSSL_CONST_BUFFERS) inBuf, #else (unsigned char *) inBuf, #endif plainBuf, mp_rsaKey, RSA_PKCS1_PADDING); if (decryptSize < 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA privateKeyDecrypt - Error Decrypting PKCS1_5 padded RSA encrypt"); } break; case XSECCryptoKeyRSA::PAD_OAEP_MGFP1 : { unsigned char * tBuf; int num = RSA_size(mp_rsaKey); XSECnew(tBuf, unsigned char[num]); ArrayJanitor<unsigned char> j_tBuf(tBuf); const EVP_MD* evp_md = NULL; const EVP_MD* mgf_md = NULL; switch (hm) { case HASH_SHA1: evp_md = EVP_get_digestbyname("SHA1"); break; case HASH_SHA224: evp_md = EVP_get_digestbyname("SHA224"); break; case HASH_SHA256: evp_md = EVP_get_digestbyname("SHA256"); break; case HASH_SHA384: evp_md = EVP_get_digestbyname("SHA384"); break; case HASH_SHA512: evp_md = EVP_get_digestbyname("SHA512"); break; } if (evp_md == NULL) { throw XSECCryptoException(XSECCryptoException::MDError, "OpenSSL:RSA - OAEP digest algorithm not supported by this version of OpenSSL"); } switch (m_mgf) { case MGF1_SHA1: mgf_md = EVP_get_digestbyname("SHA1"); break; case MGF1_SHA224: mgf_md = EVP_get_digestbyname("SHA224"); break; case MGF1_SHA256: mgf_md = EVP_get_digestbyname("SHA256"); break; case MGF1_SHA384: mgf_md = EVP_get_digestbyname("SHA384"); break; case MGF1_SHA512: mgf_md = EVP_get_digestbyname("SHA512"); break; } if (mgf_md == NULL) { throw XSECCryptoException(XSECCryptoException::MDError, "OpenSSL:RSA - MGF not supported by this version of OpenSSL"); } decryptSize = RSA_private_decrypt(inLength, #if defined(XSEC_OPENSSL_CONST_BUFFERS) inBuf, #else (unsigned char *) inBuf, #endif tBuf, mp_rsaKey, RSA_NO_PADDING); if (decryptSize < 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA privateKeyDecrypt - Error doing raw decrypt of RSA encrypted data"); } // Clear out the "0"s at the front int i; for (i = 0; i < num && tBuf[i] == 0; ++i) --decryptSize; decryptSize = RSA_padding_check_PKCS1_OAEP(plainBuf, maxOutLength, &tBuf[i], decryptSize, num, mp_oaepParams, m_oaepParamsLen, evp_md, mgf_md); if (decryptSize < 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA privateKeyDecrypt - Error removing OAEPadding"); } } break; default : throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA - Unknown padding method"); } #if 0 /* normally commented out code to determine endian problems */ int i; unsigned char t[512]; if (decryptSize < 512) { memcpy(t, plainBuf, decryptSize); for (i = 0; i < decryptSize;++i) { plainBuf[i] = t[decryptSize - 1 - i]; } } #endif return decryptSize; }
bool OpenSSLCryptoKeyRSA::verifySHA1PKCS1Base64Signature(const unsigned char * hashBuf, unsigned int hashLen, const char * base64Signature, unsigned int sigLen, hashMethod hm = HASH_SHA1) { // Use the currently loaded key to validate the Base64 encoded signature if (mp_rsaKey == NULL) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA - Attempt to validate signature with empty key"); } char* cleanedBase64Signature; unsigned int cleanedBase64SignatureLen = 0; cleanedBase64Signature = XSECCryptoBase64::cleanBuffer(base64Signature, sigLen, cleanedBase64SignatureLen); ArrayJanitor<char> j_cleanedBase64Signature(cleanedBase64Signature); int sigValLen; unsigned char* sigVal = new unsigned char[sigLen + 1]; ArrayJanitor<unsigned char> j_sigVal(sigVal); EVP_ENCODE_CTX m_dctx; EVP_DecodeInit(&m_dctx); int rc = EVP_DecodeUpdate(&m_dctx, sigVal, &sigValLen, (unsigned char *) cleanedBase64Signature, cleanedBase64SignatureLen); if (rc < 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA - Error during Base64 Decode"); } int t = 0; EVP_DecodeFinal(&m_dctx, &sigVal[sigValLen], &t); sigValLen += t; // Now decrypt unsigned char * decryptBuf; // Decrypt will always be longer than (RSA_len(key) - 11) decryptBuf = new unsigned char [RSA_size(mp_rsaKey)]; ArrayJanitor<unsigned char> j_decryptBuf(decryptBuf); // Note at this time only supports PKCS1 padding // As that is what is defined in the standard. // If this ever changes we will need to pass some paramaters // into this function to allow it to determine what the // padding should be and what the message digest OID should // be. int decryptSize = RSA_public_decrypt(sigValLen, sigVal, decryptBuf, mp_rsaKey, RSA_PKCS1_PADDING); if (decryptSize < 0) { /* throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA::verify() - Error decrypting signature"); */ // Really - this is a failed signature check, not an exception! return false; } /* Check the OID */ int oidLen = 0; unsigned char * oid = getRSASigOID(hm, oidLen); if (oid == NULL) { throw XSECCryptoException(XSECCryptoException::RSAError, "OpenSSL:RSA::verify() - Unsupported HASH algorithm for RSA"); } if (decryptSize != (int) (oidLen + hashLen) || hashLen != oid[oidLen-1]) { return false; } for (t = 0; t < oidLen; ++t) { if (oid[t] != decryptBuf[t]) { return false; } } for (;t < decryptSize; ++t) { if (hashBuf[t-oidLen] != decryptBuf[t]) { return false; } } // All OK return true; }
bool OpenSSLCryptoKeyDSA::verifyBase64Signature(unsigned char * hashBuf, unsigned int hashLen, char * base64Signature, unsigned int sigLen) { // Use the currently loaded key to validate the Base64 encoded signature if (mp_dsaKey == NULL) { throw XSECCryptoException(XSECCryptoException::DSAError, "OpenSSL:DSA - Attempt to validate signature with empty key"); } unsigned char sigVal[512]; int sigValLen; int err; /* BIO * b64 = BIO_new(BIO_f_base64()); BIO * bmem = BIO_new(BIO_s_mem()); BIO_set_mem_eof_return(bmem, 0); b64 = BIO_push(b64, bmem); // Translate signature from Base64 BIO_write(bmem, base64Signature, sigLen); sigValLen = BIO_read(b64, sigVal, 512); */ EVP_ENCODE_CTX m_dctx; int rc; EVP_DecodeInit(&m_dctx); rc = EVP_DecodeUpdate(&m_dctx, sigVal, &sigValLen, (unsigned char *) base64Signature, sigLen); if (rc < 0) { throw XSECCryptoException(XSECCryptoException::DSAError, "OpenSSL:DSA - Error during Base64 Decode"); } int t = 0; EVP_DecodeFinal(&m_dctx, &sigVal[sigValLen], &t); sigValLen += t; if (sigValLen != 40) { throw XSECCryptoException(XSECCryptoException::DSAError, "OpenSSL:DSA - Signature Length incorrect"); } // Translate to BNs and thence to DSA_SIG BIGNUM * R = BN_bin2bn(sigVal, 20, NULL); BIGNUM * S = BN_bin2bn(&sigVal[20], 20, NULL); DSA_SIG * dsa_sig = DSA_SIG_new(); dsa_sig->r = BN_dup(R); dsa_sig->s = BN_dup(S); unsigned char sigValTranslatedBuf[256]; unsigned char * sigValTranslated = sigValTranslatedBuf; int sigValTranslatedLen; sigValTranslatedLen = i2d_DSA_SIG(dsa_sig, &sigValTranslated); // Now we have a signature and a key - lets check err = DSA_do_verify(hashBuf, hashLen, dsa_sig, mp_dsaKey); DSA_SIG_free(dsa_sig); if (err < 0) { throw XSECCryptoException(XSECCryptoException::DSAError, "OpenSSL:DSA - Error validating signature"); } return (err == 1); }
unsigned int NSSCryptoKeyRSA::publicEncrypt(const unsigned char * inBuf, unsigned char * cipherBuf, unsigned int inLength, unsigned int maxOutLength, PaddingType padding, hashMethod hm) { // Perform an encrypt if (mp_pubkey == 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Attempt to encrypt data with empty key"); } unsigned int encryptSize = SECKEY_PublicKeyStrength(mp_pubkey); if (maxOutLength < encryptSize) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Too small buffer for encrypted buffer output"); } SECStatus s; unsigned char * buf; XSECnew(buf, unsigned char[encryptSize]); ArrayJanitor<unsigned char> j_buf(buf); switch (padding) { case XSECCryptoKeyRSA::PAD_PKCS_1_5 : // do the padding (http://www.w3.org/TR/xmlenc-core/#rsa-1_5) { // generate random data for padding SECStatus s = PK11_GenerateRandom(buf, encryptSize); if (s != SECSuccess) { throw XSECException(XSECException::InternalError, "NSSCryptoKeyRSA() - Error generating Random data"); } // first byte have to be 0x02 buf[0] = 0x00; buf[1] = 0x02; // check that there are no 0x00 bytes among random data for (unsigned int i = 2; i < encryptSize - inLength - 1; i++) { while (buf[i] == 0x00) { // replace all 0x00 occurences in random data with random value PK11_GenerateRandom(&buf[i], 1); } } // before key add 0x00 byte buf[encryptSize - inLength - 1] = 0x00; // at the end of input buffer (to be encrypted) add key memcpy(&buf[encryptSize - inLength], inBuf, inLength); } // encrypt s = PK11_PubEncryptRaw(mp_pubkey, cipherBuf, (unsigned char*)buf, encryptSize, NULL); if (s != SECSuccess) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA publicKeyEncrypt - Error performing encrypt"); } break; case XSECCryptoKeyRSA::PAD_OAEP_MGFP1 : throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - OAEP padding method not supported in NSS yet"); break; default : throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Unknown padding method"); } return encryptSize; }
bool NSSCryptoKeyRSA::verifySHA1PKCS1Base64Signature(const unsigned char * hashBuf, unsigned int hashLen, const char * base64Signature, unsigned int sigLen, hashMethod hm) { // Use the currently loaded key to validate the Base64 encoded signature if (mp_pubkey == 0) { // Try to import from the parameters importKey(); if (mp_pubkey == 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Attempt to validate signature with empty key"); } } // Decode the signature unsigned char * rawSig; unsigned int rawSigLen; XSECnew(rawSig, unsigned char[sigLen]); ArrayJanitor<unsigned char> j_rawSig(rawSig); // Decode the signature XSCryptCryptoBase64 b64; b64.decodeInit(); rawSigLen = b64.decode((unsigned char *) base64Signature, sigLen, rawSig, sigLen); rawSigLen += b64.decodeFinish(&rawSig[rawSigLen], sigLen - rawSigLen); SECItem signature; signature.type = siBuffer; signature.data = rawSig; signature.len = rawSigLen; SECItem data; data.data = 0; data.len = 0; SECOidTag hashalg; PRArenaPool * arena = 0; SGNDigestInfo *di = 0; SECItem * res; switch (hm) { case (HASH_MD5): hashalg = SEC_OID_MD5; break; case (HASH_SHA1): hashalg = SEC_OID_SHA1; break; case (HASH_SHA256): hashalg = SEC_OID_SHA256; break; case (HASH_SHA384): hashalg = SEC_OID_SHA384; break; case (HASH_SHA512): hashalg = SEC_OID_SHA512; break; default: throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Unsupported hash algorithm in RSA sign"); } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Error creating arena"); } di = SGN_CreateDigestInfo(hashalg, (unsigned char * )hashBuf, hashLen); if (di == NULL) { PORT_FreeArena(arena, PR_FALSE); throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Error creating digest info"); } res = SEC_ASN1EncodeItem(arena, &data, di, NSS_Get_sgn_DigestInfoTemplate(NULL, 0)); if (!res) { SGN_DestroyDigestInfo(di); PORT_FreeArena(arena, PR_FALSE); throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Error encoding digest info for RSA sign"); } // Verify signature SECStatus s = PK11_Verify(mp_pubkey, &signature, &data, NULL); return s == SECSuccess; }
unsigned int NSSCryptoKeyRSA::signSHA1PKCS1Base64Signature(unsigned char * hashBuf, unsigned int hashLen, char * base64SignatureBuf, unsigned int base64SignatureBufLen, hashMethod hm) { // Sign a pre-calculated hash using this key if (mp_privkey == 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Attempt to sign data using a public or un-loaded key"); } unsigned char * rawSig; XSECnew(rawSig, unsigned char[base64SignatureBufLen]); ArrayJanitor<unsigned char> j_rawSig(rawSig); SECItem signature; signature.type = siBuffer; signature.data = rawSig; signature.len = base64SignatureBufLen; SECItem data; data.data = 0; SECOidTag hashalg; PRArenaPool * arena = 0; SGNDigestInfo *di = 0; SECItem * res; switch (hm) { case (HASH_MD5): hashalg = SEC_OID_MD5; break; case (HASH_SHA1): hashalg = SEC_OID_SHA1; break; case (HASH_SHA256): hashalg = SEC_OID_SHA256; break; case (HASH_SHA384): hashalg = SEC_OID_SHA384; break; case (HASH_SHA512): hashalg = SEC_OID_SHA512; break; default: throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Unsupported hash algorithm in RSA sign"); } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Error creating arena"); } di = SGN_CreateDigestInfo(hashalg, hashBuf, hashLen); if (di == NULL) { PORT_FreeArena(arena, PR_FALSE); throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Error creating digest info"); } res = SEC_ASN1EncodeItem(arena, &data, di, NSS_Get_sgn_DigestInfoTemplate(NULL, 0)); if (!res) { SGN_DestroyDigestInfo(di); PORT_FreeArena(arena, PR_FALSE); throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Error encoding digest info for RSA sign"); } /* data.type = siBuffer; data.data = hashBuf; data.len = hashLen;*/ /* As of V1.3.1 - create a DigestInfo block */ SECStatus s = PK11_Sign(mp_privkey, &signature, &data); SGN_DestroyDigestInfo(di); PORT_FreeArena(arena, PR_FALSE); if (s != SECSuccess) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Error during signing operation"); } // Now encode XSCryptCryptoBase64 b64; b64.encodeInit(); unsigned int ret = b64.encode(signature.data, signature.len, (unsigned char *) base64SignatureBuf, base64SignatureBufLen); ret += b64.encodeFinish((unsigned char *) &base64SignatureBuf[ret], base64SignatureBufLen - ret); return ret; }
unsigned int NSSCryptoKeyRSA::privateDecrypt(const unsigned char * inBuf, unsigned char * plainBuf, unsigned int inLength, unsigned int maxOutLength, PaddingType padding, hashMethod hm) { // Perform a decrypt if (mp_privkey == 0) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Attempt to decrypt data with empty key"); } unsigned int decryptSize = inLength; SECStatus s; unsigned char *ptr = NULL; switch (padding) { case XSECCryptoKeyRSA::PAD_PKCS_1_5 : s = PK11_PubDecryptRaw(mp_privkey, plainBuf, (unsigned int*)&decryptSize, maxOutLength, (unsigned char*)inBuf, inLength); if (s != SECSuccess) { throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA privateKeyDecrypt - Error Decrypting PKCS1_5 padded RSA encrypt"); } //do the padding (http://www.w3.org/TR/xmlenc-core/#rsa-1_5) ptr = (unsigned char*) memchr(plainBuf, 0x02, decryptSize); if( ptr ) { unsigned int bytesToRemove = ((ptr-plainBuf)+1); memmove(plainBuf, ptr+1, decryptSize-bytesToRemove); decryptSize -= bytesToRemove; } ptr = (unsigned char*) memchr(plainBuf, 0x00, decryptSize); if( ptr ) { unsigned int bytesToRemove = ((ptr-plainBuf)+1); memmove(plainBuf, ptr+1, decryptSize-bytesToRemove); decryptSize -= bytesToRemove; } break; case XSECCryptoKeyRSA::PAD_OAEP_MGFP1 : throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - OAEP padding method not supported in NSS yet"); break; default : throw XSECCryptoException(XSECCryptoException::RSAError, "NSS:RSA - Unknown padding method"); } return decryptSize; }
XSECCryptoSymmetricKey * OpenPGPCryptoProvider::keySymmetric(XSECCryptoSymmetricKey::SymmetricKeyType alg) const { throw XSECCryptoException(XSECCryptoException::UnsupportedError, "OpenPGPCryptoProvider::keySymmetric - Symmetric cipher support not available"); }