Commit cc08259d authored by Vasilii Sukhanov's avatar Vasilii Sukhanov Committed by Commit Bot

Add ECCommutativeCipher encrypt/decrypt functions.

Bug: 986298
Change-Id: Idbac7135d6ed958529bea6968d4405f5e689c84b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1746476Reviewed-by: default avatarIoana Pandele <ioanap@chromium.org>
Commit-Queue: Vasilii Sukhanov <vasilii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#686356}
parent 0f4c96b1
...@@ -90,5 +90,6 @@ jumbo_source_set("unit_tests") { ...@@ -90,5 +90,6 @@ jumbo_source_set("unit_tests") {
"//services/network:test_support", "//services/network:test_support",
"//testing/gmock", "//testing/gmock",
"//testing/gtest", "//testing/gtest",
"//third_party/private-join-and-compute/src:ec_commutative_cipher",
] ]
} }
include_rules = [ include_rules = [
"+components/signin/public", "+components/signin/public",
"+third_party/private-join-and-compute/src",
] ]
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include "crypto/openssl_util.h" #include "crypto/openssl_util.h"
#include "crypto/sha2.h" #include "crypto/sha2.h"
#include "third_party/boringssl/src/include/openssl/evp.h" #include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/nid.h"
#include "third_party/private-join-and-compute/src/crypto/ec_commutative_cipher.h"
namespace password_manager { namespace password_manager {
...@@ -76,4 +78,37 @@ std::string ScryptHashUsernameAndPassword(base::StringPiece username, ...@@ -76,4 +78,37 @@ std::string ScryptHashUsernameAndPassword(base::StringPiece username,
return scrypt_ok == 1 ? std::move(result) : std::string(); return scrypt_ok == 1 ? std::move(result) : std::string();
} }
std::string CipherEncrypt(const std::string& plaintext, std::string* key) {
using ::private_join_and_compute::ECCommutativeCipher;
auto cipher = ECCommutativeCipher::CreateWithNewKey(
NID_X9_62_prime256v1, ECCommutativeCipher::SHA256);
*key = cipher.ValueOrDie()->GetPrivateKeyBytes();
auto result = cipher.ValueOrDie()->Encrypt(plaintext);
if (result.ok())
return result.ValueOrDie();
return std::string();
}
std::string CipherEncryptWithKey(const std::string& plaintext,
const std::string& key) {
using ::private_join_and_compute::ECCommutativeCipher;
auto cipher = ECCommutativeCipher::CreateFromKey(NID_X9_62_prime256v1, key,
ECCommutativeCipher::SHA256);
auto result = cipher.ValueOrDie()->Encrypt(plaintext);
if (result.ok())
return result.ValueOrDie();
return std::string();
}
std::string CipherDecrypt(const std::string& ciphertext,
const std::string& key) {
using ::private_join_and_compute::ECCommutativeCipher;
auto cipher = ECCommutativeCipher::CreateFromKey(NID_X9_62_prime256v1, key,
ECCommutativeCipher::SHA256);
auto result = cipher.ValueOrDie()->Decrypt(ciphertext);
if (result.ok())
return result.ValueOrDie();
return std::string();
}
} // namespace password_manager } // namespace password_manager
...@@ -32,6 +32,19 @@ std::string BucketizeUsername(base::StringPiece canonicalized_username); ...@@ -32,6 +32,19 @@ std::string BucketizeUsername(base::StringPiece canonicalized_username);
std::string ScryptHashUsernameAndPassword(base::StringPiece username, std::string ScryptHashUsernameAndPassword(base::StringPiece username,
base::StringPiece password); base::StringPiece password);
// Encrypt/decrypt routines.
// Encrypts |plaintext| with a new key. The key is returned via |key|.
std::string CipherEncrypt(const std::string& plaintext, std::string* key);
// Encrypts |plaintext| with the existing key.
std::string CipherEncryptWithKey(const std::string& plaintext,
const std::string& key);
// Decrypts |ciphertext| using |key|.
std::string CipherDecrypt(const std::string& ciphertext,
const std::string& key);
} // namespace password_manager } // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_ENCRYPTION_UTILS_H_ #endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_ENCRYPTION_UTILS_H_
...@@ -4,12 +4,49 @@ ...@@ -4,12 +4,49 @@
#include "components/password_manager/core/browser/leak_detection/encryption_utils.h" #include "components/password_manager/core/browser/leak_detection/encryption_utils.h"
#include <vector>
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/private-join-and-compute/src/crypto/context.h"
#include "third_party/private-join-and-compute/src/crypto/ec_commutative_cipher.h"
#include "third_party/private-join-and-compute/src/crypto/ec_group.h"
#include "third_party/private-join-and-compute/src/crypto/ec_point.h"
namespace password_manager { namespace password_manager {
namespace {
// Returns the hash of |plaintext| used by the encryption algorithm.
std::string CalculateECCurveHash(const std::string& plaintext) {
using ::private_join_and_compute::Context;
using ::private_join_and_compute::ECGroup;
std::unique_ptr<Context> context(new Context);
auto group = ECGroup::Create(NID_X9_62_prime256v1, context.get());
auto point = group.ValueOrDie().GetPointByHashingToCurveSha256(plaintext);
return point.ValueOrDie().ToBytesCompressed().ValueOrDie();
}
// |already_encrypted| is an already encrypted string (output of CipherEncrypt).
// Encrypts it again with a new key. The key is returned in |key|.
std::string CipherReEncrypt(const std::string& already_encrypted,
std::string* key) {
using ::private_join_and_compute::ECCommutativeCipher;
auto cipher = ECCommutativeCipher::CreateWithNewKey(
NID_X9_62_prime256v1, ECCommutativeCipher::SHA256);
*key = cipher.ValueOrDie()->GetPrivateKeyBytes();
auto result = cipher.ValueOrDie()->ReEncrypt(already_encrypted);
return result.ValueOrDie();
}
// Converts a string to an array for printing.
std::vector<int> StringAsArray(const std::string& s) {
return std::vector<int>(s.begin(), s.end());
}
} // namespace
using ::testing::ElementsAreArray; using ::testing::ElementsAreArray;
...@@ -56,4 +93,59 @@ TEST(EncryptionUtils, ScryptHashUsernameAndPassword) { ...@@ -56,4 +93,59 @@ TEST(EncryptionUtils, ScryptHashUsernameAndPassword) {
EXPECT_THAT(result, ElementsAreArray(kExpected)); EXPECT_THAT(result, ElementsAreArray(kExpected));
} }
TEST(EncryptionUtils, EncryptAndDecrypt) {
constexpr char kRandomString[] = "very_secret";
std::string key;
std::string cipher = CipherEncrypt(kRandomString, &key);
SCOPED_TRACE(testing::Message()
<< "key=" << testing::PrintToString(StringAsArray(key)));
EXPECT_NE(kRandomString, cipher);
EXPECT_NE(std::string(), key);
EXPECT_THAT(CalculateECCurveHash(kRandomString),
ElementsAreArray(CipherDecrypt(cipher, key)));
}
TEST(EncryptionUtils, EncryptAndDecryptWithPredefinedKey) {
constexpr char kRandomString[] = "very_secret";
const std::string kKey = {-3, -80, 44, -113, -1, -67, 49, -120,
-91, 54, -15, -2, 13, -87, 95, 85,
-101, 11, -81, 102, -105, -14, 8, -123,
1, 36, -74, -19, 88, 109, -24, -102};
SCOPED_TRACE(testing::Message()
<< "key=" << testing::PrintToString(StringAsArray(kKey)));
// The expected result was obtained by running the Java implementation of the
// cipher.
const char kEncrypted[] = {2, 69, 19, 106, -38, 4, -21, -57, 110,
95, 110, 111, 51, -100, -56, -10, -24, 71,
-112, -64, 58, -64, 76, -35, -117, -23, -100,
25, 63, 37, 114, 74, 88};
std::string cipher = CipherEncryptWithKey(kRandomString, kKey);
EXPECT_THAT(cipher, ElementsAreArray(kEncrypted));
EXPECT_THAT(CalculateECCurveHash(kRandomString),
ElementsAreArray(CipherDecrypt(cipher, kKey)));
}
TEST(EncryptionUtils, CipherIsCommutative) {
constexpr char kRandomString[] = "very_secret";
// Client encrypts the string.
std::string key_client;
std::string cipher = CipherEncrypt(kRandomString, &key_client);
SCOPED_TRACE(testing::Message()
<< "key_client="
<< testing::PrintToString(StringAsArray(key_client)));
// Server encrypts the result.
std::string key_server;
cipher = CipherReEncrypt(cipher, &key_server);
SCOPED_TRACE(testing::Message()
<< "key_server="
<< testing::PrintToString(StringAsArray(key_server)));
EXPECT_THAT(CipherEncryptWithKey(kRandomString, key_server),
ElementsAreArray(CipherDecrypt(cipher, key_client)));
}
} // namespace password_manager } // namespace password_manager
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment