+ if (1 != RAND_bytes(civ.data(), civ.size()))
+ ThrowErr(Exc::Crypto::InternalError, "RAND_bytes failed to generate IV.");
+ return civ;
+}
+
+RawBuffer passwordToKey(const Password &password, const RawBuffer &salt, size_t keySize)
+{
+ RawBuffer result(keySize);
+
+ if (1 != PKCS5_PBKDF2_HMAC_SHA1(
+ password.c_str(),
+ password.size(),
+ salt.data(),
+ salt.size(),
+ ITERATIONS,
+ result.size(),
+ result.data()))
+ {
+ ThrowErr(Exc::InternalError, "PCKS5_PKKDF2_HMAC_SHA1 failed.");
+ }
+
+ return result;
+}
+
+RawBuffer unpack(const RawBuffer& packed, const Password& pass)
+{
+ MessageBuffer buffer;
+ buffer.Push(packed);
+ int encryptionScheme = 0;
+ RawBuffer data;
+ buffer.Deserialize(encryptionScheme, data);
+
+ if (encryptionScheme == 0)
+ return data;
+
+ MessageBuffer internalBuffer;
+ internalBuffer.Push(data);
+ RawBuffer encrypted;
+ RawBuffer iv;
+ RawBuffer tag;
+
+ // serialization exceptions will be catched as CKM::Exception and will cause
+ // CKM_API_ERROR_SERVER_ERROR
+ internalBuffer.Deserialize(encrypted, iv, tag);
+
+ /*
+ * AES GCM will check data integrity and handle cases where:
+ * - wrong password is used
+ * - password is empty when it shouldn't be
+ * - password is not empty when it should be
+ */
+ RawBuffer key = passwordToKey(pass, iv, KEY_LENGTH);
+
+ RawBuffer ret;
+ try {
+ ret = Crypto::SW::Internals::decryptDataAesGcm(key, encrypted, iv, tag);
+ } catch( const Exc::Crypto::InternalError& e) {
+ ThrowErr(Exc::AuthenticationFailed, "Decryption with custom password failed");
+ }
+ return ret;
+}
+
+RawBuffer pack(const RawBuffer& data, const Password& pass)
+{
+ int scheme = EncryptionScheme::NONE;
+ RawBuffer packed = data;
+ if (!pass.empty()) {
+ RawBuffer iv = generateRandIV();
+ RawBuffer key = passwordToKey(pass, iv, KEY_LENGTH);
+
+ std::pair<RawBuffer, RawBuffer> ret;
+ try {
+ ret = Crypto::SW::Internals::encryptDataAesGcm(key, data, iv, STORE_AES_GCM_TAG_SIZE);
+ } catch( const Exc::Crypto::InternalError& e) {
+ ThrowErr(Exc::AuthenticationFailed, "Encryption with custom password failed");
+ }
+ scheme |= EncryptionScheme::PASSWORD;
+
+ // serialization exceptions will be catched as CKM::Exception and will cause
+ // CKM_API_ERROR_SERVER_ERROR
+ packed = MessageBuffer::Serialize(ret.first, iv, ret.second).Pop();
+ }
+ // encryption scheme + internal buffer
+ return MessageBuffer::Serialize(scheme, packed).Pop();
+}
+
+} // namespace anonymous