[GCrypt] Implement AES_KW support
authorzandobersek@gmail.com <zandobersek@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 3 Apr 2017 18:36:03 +0000 (18:36 +0000)
committerzandobersek@gmail.com <zandobersek@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 3 Apr 2017 18:36:03 +0000 (18:36 +0000)
https://bugs.webkit.org/show_bug.cgi?id=170274

Reviewed by Michael Catanzaro.

Implement the CryptoAlgorithmAES_KW::platform{Wrap,Unwrap}Key()
functionality for configurations that use libgcrypt. This is done
by leveraging the gcry_cipher_* APIs for the AES algorithm that's
deducted appropriately from the key size and the AESWRAP cipher mode.

No new tests -- current ones cover this sufficiently, but are not yet
enabled due to other missing platform-specific SUBTLE_CRYPTO
implementations.

* crypto/gcrypt/CryptoAlgorithmAES_KWGCrypt.cpp:
(WebCore::gcryptWrapKey):
(WebCore::gcryptUnwrapKey):
(WebCore::CryptoAlgorithmAES_KW::platformWrapKey):
(WebCore::CryptoAlgorithmAES_KW::platformUnwrapKey):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@214823 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/crypto/gcrypt/CryptoAlgorithmAES_KWGCrypt.cpp

index 3b21ff3..d0b961c 100644 (file)
@@ -1,5 +1,27 @@
 2017-04-03  Zan Dobersek  <zdobersek@igalia.com>
 
+        [GCrypt] Implement AES_KW support
+        https://bugs.webkit.org/show_bug.cgi?id=170274
+
+        Reviewed by Michael Catanzaro.
+
+        Implement the CryptoAlgorithmAES_KW::platform{Wrap,Unwrap}Key()
+        functionality for configurations that use libgcrypt. This is done
+        by leveraging the gcry_cipher_* APIs for the AES algorithm that's
+        deducted appropriately from the key size and the AESWRAP cipher mode.
+
+        No new tests -- current ones cover this sufficiently, but are not yet
+        enabled due to other missing platform-specific SUBTLE_CRYPTO
+        implementations.
+
+        * crypto/gcrypt/CryptoAlgorithmAES_KWGCrypt.cpp:
+        (WebCore::gcryptWrapKey):
+        (WebCore::gcryptUnwrapKey):
+        (WebCore::CryptoAlgorithmAES_KW::platformWrapKey):
+        (WebCore::CryptoAlgorithmAES_KW::platformUnwrapKey):
+
+2017-04-03  Zan Dobersek  <zdobersek@igalia.com>
+
         [GCrypt] Implement AES_GCM support
         https://bugs.webkit.org/show_bug.cgi?id=170271
 
index 9a58b64..d3921dc 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2014 Igalia S.L. All rights reserved.
+ * Copyright (C) 2017 Metrological Group B.V.
+ * Copyright (C) 2017 Igalia S.L.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #if ENABLE(SUBTLE_CRYPTO)
 
+#include "CryptoKeyAES.h"
 #include "ExceptionCode.h"
 #include "NotImplemented.h"
+#include <pal/crypto/gcrypt/Handle.h>
+#include <pal/crypto/gcrypt/Utilities.h>
 
 namespace WebCore {
 
-void CryptoAlgorithmAES_KW::platformWrapKey(Ref<CryptoKey>&&, Vector<uint8_t>&&, VectorCallback&&, ExceptionCallback&&)
+static std::optional<Vector<uint8_t>> gcryptWrapKey(const Vector<uint8_t>& key, const Vector<uint8_t>& data)
 {
-    notImplemented();
+    auto algorithm = PAL::GCrypt::aesAlgorithmForKeySize(key.size() * 8);
+    if (!algorithm)
+        return std::nullopt;
+
+    PAL::GCrypt::Handle<gcry_cipher_hd_t> handle;
+    gcry_error_t error = gcry_cipher_open(&handle, *algorithm, GCRY_CIPHER_MODE_AESWRAP, 0);
+    if (error != GPG_ERR_NO_ERROR) {
+        PAL::GCrypt::logError(error);
+        return std::nullopt;
+    }
+
+    error = gcry_cipher_setkey(handle, key.data(), key.size());
+    if (error != GPG_ERR_NO_ERROR) {
+        PAL::GCrypt::logError(error);
+        return std::nullopt;
+    }
+
+    error = gcry_cipher_final(handle);
+    if (error != GPG_ERR_NO_ERROR) {
+        PAL::GCrypt::logError(error);
+        return std::nullopt;
+    }
+
+    // On encryption the provided output buffer must be 64 bit (8 byte) larger than the input buffer.
+    Vector<uint8_t> output(data.size() + 8);
+    error = gcry_cipher_encrypt(handle, output.data(), output.size(), data.data(), data.size());
+    if (error != GPG_ERR_NO_ERROR) {
+        PAL::GCrypt::logError(error);
+        return std::nullopt;
+    }
+
+    return output;
 }
 
-void CryptoAlgorithmAES_KW::platformUnwrapKey(Ref<CryptoKey>&&, Vector<uint8_t>&&, VectorCallback&&, ExceptionCallback&&)
+static std::optional<Vector<uint8_t>> gcryptUnwrapKey(const Vector<uint8_t>& key, const Vector<uint8_t>& data)
 {
-    notImplemented();
+    auto algorithm = PAL::GCrypt::aesAlgorithmForKeySize(key.size() * 8);
+    if (!algorithm)
+        return std::nullopt;
+
+    PAL::GCrypt::Handle<gcry_cipher_hd_t> handle;
+    gcry_error_t error = gcry_cipher_open(&handle, *algorithm, GCRY_CIPHER_MODE_AESWRAP, 0);
+    if (error != GPG_ERR_NO_ERROR) {
+        PAL::GCrypt::logError(error);
+        return std::nullopt;
+    }
+
+    error = gcry_cipher_setkey(handle, key.data(), key.size());
+    if (error != GPG_ERR_NO_ERROR) {
+        PAL::GCrypt::logError(error);
+        return std::nullopt;
+    }
+
+    error = gcry_cipher_final(handle);
+    if (error != GPG_ERR_NO_ERROR) {
+        PAL::GCrypt::logError(error);
+        return std::nullopt;
+    }
+
+    // On decryption the output buffer may be specified 64 bit (8 byte) shorter than then input buffer.
+    Vector<uint8_t> output(data.size() - 8);
+    error = gcry_cipher_decrypt(handle, output.data(), output.size(), data.data(), data.size());
+    if (error != GPG_ERR_NO_ERROR) {
+        PAL::GCrypt::logError(error);
+        return std::nullopt;
+    }
+
+    return output;
+}
+
+void CryptoAlgorithmAES_KW::platformWrapKey(Ref<CryptoKey>&& key, Vector<uint8_t>&& data, VectorCallback&& callback, ExceptionCallback&& exceptionCallback)
+{
+    auto& aesKey = downcast<CryptoKeyAES>(key.get());
+    auto output = gcryptWrapKey(aesKey.key(), data);
+    if (!output) {
+        exceptionCallback(OperationError);
+        return;
+    }
+
+    callback(*output);
+}
+
+void CryptoAlgorithmAES_KW::platformUnwrapKey(Ref<CryptoKey>&& key, Vector<uint8_t>&& data, VectorCallback&& callback, ExceptionCallback&& exceptionCallback)
+{
+    auto& aesKey = downcast<CryptoKeyAES>(key.get());
+    auto output = gcryptUnwrapKey(aesKey.key(), data);
+    if (!output) {
+        exceptionCallback(OperationError);
+        return;
+    }
+
+    callback(*output);
 }
 
 ExceptionOr<void> CryptoAlgorithmAES_KW::platformEncrypt(const CryptoKeyAES&, const CryptoOperationData&, VectorCallback&&, VoidCallback&&)