Blob PrivateKey::decrypt(const Blob& cipher) const { if (!key) throw CryptoException("Can't decrypt data without private key !"); unsigned key_len = 0; int err = gnutls_privkey_get_pk_algorithm(key, &key_len); if (err < 0) throw CryptoException("Can't read public key length !"); if (err != GNUTLS_PK_RSA) throw CryptoException("Must be an RSA key"); unsigned cypher_block_sz = key_len / 8; if (cipher.size() % cypher_block_sz) throw CryptoException("Unexpected cipher length"); Blob ret; for (auto cb = cipher.cbegin(), ce = cipher.cend(); cb < ce; cb += cypher_block_sz) { const gnutls_datum_t dat {(uint8_t*)(&(*cb)), cypher_block_sz}; gnutls_datum_t out; int err = gnutls_privkey_decrypt_data(key, 0, &dat, &out); if (err != GNUTLS_E_SUCCESS) throw DhtException(std::string("Can't decrypt data: ") + gnutls_strerror(err)); ret.insert(ret.end(), out.data, out.data+out.size); gnutls_free(out.data); } return ret; }
Blob PublicKey::encrypt(const Blob& data) const { if (!pk) throw CryptoException("Can't read public key !"); unsigned key_len = 0; int err = gnutls_pubkey_get_pk_algorithm(pk, &key_len); if (err < 0) throw CryptoException("Can't read public key length !"); if (err != GNUTLS_PK_RSA) throw CryptoException("Must be an RSA key"); unsigned max_block_sz = key_len / 8 - 11; unsigned cypher_block_sz = key_len / 8; unsigned block_num = data.empty() ? 1 : 1 + (data.size() - 1) / max_block_sz; Blob ret; auto eb = data.cbegin(); auto ee = data.cend(); for (unsigned i=0; i<block_num; i++) { auto blk_sz = std::min<unsigned>(ee - eb, max_block_sz); const gnutls_datum_t dat {(uint8_t*)&(*eb), blk_sz}; gnutls_datum_t encrypted; err = gnutls_pubkey_encrypt_data(pk, 0, &dat, &encrypted); if (err != GNUTLS_E_SUCCESS) throw CryptoException(std::string("Can't encrypt data: ") + gnutls_strerror(err)); if (encrypted.size != cypher_block_sz) throw CryptoException("Unexpected cypherblock size"); ret.insert(ret.end(), encrypted.data, encrypted.data+encrypted.size); eb += blk_sz; gnutls_free(encrypted.data); } return ret; }