Skip to content

Commit

Permalink
[TON]: Add CryptoBoxSecretKey FFIs to create from Bytes, get Bytes (#…
Browse files Browse the repository at this point in the history
…3977)

* feat(ton): Add Rust FFI to manipulate the secret's data

* feat(ton): Add C++ FFI to manipulate the secret's data

* feat(ton): Add Android, iOS tests

* [CI] Trigger CI
  • Loading branch information
satoshiotomakan authored Aug 7, 2024
1 parent 0b6bbbb commit a05c01a
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,22 @@ class TestCryptoBox {
val decrypted = CryptoBox.decryptEasy(otherSecret, myPubkey, encrypted)
assertEquals(decrypted.toString(Charsets.UTF_8), message)
}

@Test
fun testSecretKeyFromToBytes() {
val secretBytesHex = "0xdd87000d4805d6fbd89ae1352f5e4445648b79d5e901c92aebcb610e9be468e4"
val secretBytes = secretBytesHex.toHexByteArray()
assert(CryptoBoxSecretKey.isValid(secretBytes))
val secret = CryptoBoxSecretKey(secretBytes)
assertEquals(secret.data().toHex(), secretBytesHex)
}

@Test
fun testPublicKeyFromToBytes() {
val publicBytesHex = "0xafccabc5b28a8a1fd1cd880516f9c854ae2498d0d1b978b53a59f38e4ae55747"
val publicBytes = publicBytesHex.toHexByteArray()
assert(CryptoBoxPublicKey.isValid(publicBytes))
val pubkey = CryptoBoxPublicKey(publicBytes)
assertEquals(pubkey.data().toHex(), publicBytesHex)
}
}
22 changes: 22 additions & 0 deletions include/TrustWalletCore/TWCryptoBoxSecretKey.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,28 @@ TW_EXTERN_C_BEGIN
TW_EXPORT_CLASS
struct TWCryptoBoxSecretKey;

/// Determines if the given secret key is valid or not.
///
/// \param data *non-null* byte array.
/// \return true if the secret key is valid, false otherwise.
TW_EXPORT_STATIC_METHOD
bool TWCryptoBoxSecretKeyIsValid(TWData* _Nonnull data);

/// Create a random secret key.
///
/// \note Should be deleted with \tw_crypto_box_secret_key_delete.
/// \return *non-null* pointer to Secret Key.
TW_EXPORT_STATIC_METHOD
struct TWCryptoBoxSecretKey* _Nonnull TWCryptoBoxSecretKeyCreate();

/// Create a `crypto_box` secret key with the given block of data.
///
/// \param data *non-null* byte array. Expected to have 32 bytes.
/// \note Should be deleted with \tw_crypto_box_secret_key_delete.
/// \return Nullable pointer to Secret Key.
TW_EXPORT_STATIC_METHOD
struct TWCryptoBoxSecretKey* _Nullable TWCryptoBoxSecretKeyCreateWithData(TWData* _Nonnull data);

/// Delete the given secret `key`.
///
/// \param key *non-null* pointer to secret key.
Expand All @@ -35,4 +50,11 @@ void TWCryptoBoxSecretKeyDelete(struct TWCryptoBoxSecretKey* _Nonnull key);
TW_EXPORT_METHOD
struct TWCryptoBoxPublicKey* _Nonnull TWCryptoBoxSecretKeyGetPublicKey(struct TWCryptoBoxSecretKey* _Nonnull key);

/// Returns the raw data of the given secret-key.
///
/// \param secretKey *non-null* pointer to a secret key.
/// \return C-compatible result with a C-compatible byte array.
TW_EXPORT_PROPERTY
TWData* _Nonnull TWCryptoBoxSecretKeyData(struct TWCryptoBoxSecretKey* _Nonnull secretKey);

TW_EXTERN_C_END
46 changes: 45 additions & 1 deletion rust/tw_keypair/src/ffi/crypto_box/secret_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,26 @@

use crate::ffi::crypto_box::public_key::TWCryptoBoxPublicKey;
use crate::nacl_crypto_box::secret_key::SecretKey;
use tw_memory::ffi::tw_data::TWData;
use tw_memory::ffi::RawPtrTrait;
use tw_misc::try_or_else;
use tw_misc::traits::ToBytesZeroizing;
use tw_misc::{try_or_else, try_or_false};

/// Secret key used in `crypto_box` cryptography.
pub struct TWCryptoBoxSecretKey(pub(crate) SecretKey);

impl RawPtrTrait for TWCryptoBoxSecretKey {}

/// Determines if the given secret key is valid or not.
///
/// \param data *non-null* byte array.
/// \return true if the secret key is valid, false otherwise.
#[no_mangle]
pub unsafe extern "C" fn tw_crypto_box_secret_key_is_valid(data: *const TWData) -> bool {
let bytes_ref = try_or_false!(TWData::from_ptr_as_ref(data));
SecretKey::try_from(bytes_ref.as_slice()).is_ok()
}

/// Create a random secret key.
///
/// \note Should be deleted with \tw_crypto_box_secret_key_delete.
Expand All @@ -23,6 +35,23 @@ pub unsafe extern "C" fn tw_crypto_box_secret_key_create() -> *mut TWCryptoBoxSe
TWCryptoBoxSecretKey(SecretKey::random()).into_ptr()
}

/// Create a `crypto_box` secret key with the given block of data.
///
/// \param data *non-null* byte array. Expected to have 32 bytes.
/// \note Should be deleted with \tw_crypto_box_secret_key_delete.
/// \return Nullable pointer to Secret Key.
#[no_mangle]
pub unsafe extern "C" fn tw_crypto_box_secret_key_create_with_data(
data: *const TWData,
) -> *mut TWCryptoBoxSecretKey {
let bytes_ref = try_or_else!(TWData::from_ptr_as_ref(data), std::ptr::null_mut);
let secret = try_or_else!(
SecretKey::try_from(bytes_ref.as_slice()),
std::ptr::null_mut
);
TWCryptoBoxSecretKey(secret).into_ptr()
}

/// Delete the given secret `key`.
///
/// \param key *non-null* pointer to secret key.
Expand All @@ -46,3 +75,18 @@ pub unsafe extern "C" fn tw_crypto_box_secret_key_get_public_key(
);
TWCryptoBoxPublicKey(secret.0.public_key()).into_ptr()
}

/// Returns the raw data of a given secret-key.
///
/// \param secret_key *non-null* pointer to a secret key.
/// \return C-compatible result with a C-compatible byte array.
#[no_mangle]
pub unsafe extern "C" fn tw_crypto_box_secret_key_data(
secret_key: *const TWCryptoBoxSecretKey,
) -> *mut TWData {
let secret_ref = try_or_else!(
TWCryptoBoxSecretKey::from_ptr_as_ref(secret_key),
std::ptr::null_mut
);
TWData::from(secret_ref.0.to_zeroizing_vec().to_vec()).into_ptr()
}
14 changes: 14 additions & 0 deletions rust/tw_keypair/src/nacl_crypto_box/secret_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
use crate::nacl_crypto_box::public_key::PublicKey;
use crate::rand::{CryptoRngCore, OsRng};
use crate::KeyPairError;
use tw_hash::H256;
use tw_misc::traits::ToBytesZeroizing;
use zeroize::Zeroizing;

pub struct SecretKey {
secret: crypto_box::SecretKey,
Expand All @@ -27,6 +30,17 @@ impl SecretKey {
pub(crate) fn inner(&self) -> &crypto_box::SecretKey {
&self.secret
}

pub fn to_vec(&self) -> Zeroizing<H256> {
Zeroizing::new(H256::from(self.secret.to_bytes()))
}
}

impl ToBytesZeroizing for SecretKey {
fn to_zeroizing_vec(&self) -> Zeroizing<Vec<u8>> {
let bytes = Zeroizing::new(self.secret.to_bytes());
Zeroizing::new(bytes.to_vec())
}
}

impl<'a> TryFrom<&'a [u8]> for SecretKey {
Expand Down
19 changes: 18 additions & 1 deletion rust/tw_keypair/tests/crypto_box_ffi_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use tw_keypair::ffi::crypto_box::public_key::{
tw_crypto_box_public_key_is_valid,
};
use tw_keypair::ffi::crypto_box::secret_key::{
tw_crypto_box_secret_key_create, tw_crypto_box_secret_key_get_public_key,
tw_crypto_box_secret_key_create, tw_crypto_box_secret_key_create_with_data,
tw_crypto_box_secret_key_data, tw_crypto_box_secret_key_get_public_key,
tw_crypto_box_secret_key_is_valid,
};
use tw_keypair::ffi::crypto_box::{tw_crypto_box_decrypt_easy, tw_crypto_box_encrypt_easy};
use tw_keypair::test_utils::tw_crypto_box_helpers::{
Expand Down Expand Up @@ -86,3 +88,18 @@ fn test_public_key() {
let actual_data = TWDataHelper::wrap(unsafe { tw_crypto_box_public_key_data(pubkey.ptr()) });
assert_eq!(actual_data.to_vec().unwrap(), pubkey_bytes);
}

#[test]
fn test_secret_key() {
let secret_bytes = "dd87000d4805d6fbd89ae1352f5e4445648b79d5e901c92aebcb610e9be468e4"
.decode_hex()
.unwrap();

let secret_data = TWDataHelper::create(secret_bytes.clone());
assert!(unsafe { tw_crypto_box_secret_key_is_valid(secret_data.ptr()) });

let pubkey =
TWWrapper::wrap(unsafe { tw_crypto_box_secret_key_create_with_data(secret_data.ptr()) });
let actual_data = TWDataHelper::wrap(unsafe { tw_crypto_box_secret_key_data(pubkey.ptr()) });
assert_eq!(actual_data.to_vec().unwrap(), secret_bytes);
}
19 changes: 19 additions & 0 deletions src/CryptoBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,30 @@ SecretKey::SecretKey() {
impl = SecretKeyPtr(secretKey, Rust::tw_crypto_box_secret_key_delete);
}

bool SecretKey::isValid(const Data& bytes) {
Rust::TWDataWrapper data = bytes;
return Rust::tw_crypto_box_secret_key_is_valid(data.get());
}

std::optional<SecretKey> SecretKey::fromBytes(const Data& bytes) {
Rust::TWDataWrapper data = bytes;
if (!Rust::tw_crypto_box_secret_key_is_valid(data.get())) {
return std::nullopt;
}
auto* secretKey = Rust::tw_crypto_box_secret_key_create_with_data(data.get());
return SecretKey(SecretKeyPtr(secretKey, Rust::tw_crypto_box_secret_key_delete));
}

PublicKey SecretKey::getPublicKey() const noexcept {
auto* publicKey = Rust::tw_crypto_box_secret_key_get_public_key(impl.get());
return PublicKey(PublicKeyPtr(publicKey, Rust::tw_crypto_box_public_key_delete));
}

Data SecretKey::getData() const {
Rust::TWDataWrapper data = Rust::tw_crypto_box_secret_key_data(impl.get());
return data.toDataOrDefault();
}

Data encryptEasy(const SecretKey& mySecret, const PublicKey& otherPubkey, const Data& message) {
Rust::TWDataWrapper messageData = message;
Rust::TWDataWrapper encrypted = Rust::tw_crypto_box_encrypt_easy(mySecret.impl.get(), otherPubkey.impl.get(), messageData.get());
Expand Down
12 changes: 12 additions & 0 deletions src/CryptoBox.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,21 @@ class SecretKey {
/// Create a random secret key.
SecretKey();

explicit SecretKey(SecretKeyPtr ptr): impl(std::move(ptr)) {
}

/// Determines if the given secret key is valid or not.
static bool isValid(const Data& bytes);

/// Create a `crypto_box` secret key with the given block of data.
static std::optional<SecretKey> fromBytes(const Data& bytes);

/// Returns the public key associated with the given `key`.
PublicKey getPublicKey() const noexcept;

/// Returns the raw data of the given secret-key.
Data getData() const;

SecretKeyPtr impl;
};

Expand Down
19 changes: 19 additions & 0 deletions src/interface/TWCryptoBoxSecretKey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@

using namespace TW;

bool TWCryptoBoxSecretKeyIsValid(TWData* _Nonnull data) {
auto& bytes = *reinterpret_cast<const Data*>(data);
return CryptoBox::SecretKey::isValid(bytes);
}

struct TWCryptoBoxSecretKey* _Nullable TWCryptoBoxSecretKeyCreateWithData(TWData* _Nonnull data) {
auto& bytes = *reinterpret_cast<const Data*>(data);
auto secretKey = CryptoBox::SecretKey::fromBytes(bytes);
if (!secretKey) {
return nullptr;
}
return new TWCryptoBoxSecretKey { secretKey.value() };
}

struct TWCryptoBoxSecretKey* _Nonnull TWCryptoBoxSecretKeyCreate() {
CryptoBox::SecretKey secretKey;
return new TWCryptoBoxSecretKey { secretKey };
Expand All @@ -20,3 +34,8 @@ struct TWCryptoBoxPublicKey* TWCryptoBoxSecretKeyGetPublicKey(struct TWCryptoBox
auto publicKey = key->impl.getPublicKey();
return new TWCryptoBoxPublicKey { publicKey };
}

TWData* _Nonnull TWCryptoBoxSecretKeyData(struct TWCryptoBoxSecretKey* _Nonnull secretKey) {
auto bytes = secretKey->impl.getData();
return TWDataCreateWithBytes(bytes.data(), bytes.size());
}
14 changes: 14 additions & 0 deletions swift/Tests/CryptoBoxTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,18 @@ class CryptoBoxTests: XCTestCase {
let decryptedStr = String(bytes: decrypted, encoding: .utf8)
XCTAssertEqual(decryptedStr, message)
}

func testSecretKeyFromToBytes() {
let secretBytes = Data(hexString: "dd87000d4805d6fbd89ae1352f5e4445648b79d5e901c92aebcb610e9be468e4")!
XCTAssert(CryptoBoxSecretKey.isValid(data: secretBytes))
let secret = CryptoBoxSecretKey(data: secretBytes)
XCTAssertEqual(secret?.data, secretBytes)
}

func testPublicKeyFromToBytes() {
let publicBytes = Data(hexString: "afccabc5b28a8a1fd1cd880516f9c854ae2498d0d1b978b53a59f38e4ae55747")!
XCTAssert(CryptoBoxPublicKey.isValid(data: publicBytes))
let pubkey = CryptoBoxPublicKey(data: publicBytes)
XCTAssertEqual(pubkey?.data, publicBytes)
}
}
10 changes: 10 additions & 0 deletions tests/interface/TWCryptoBoxTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ TEST(TWCryptoBox, PublicKeyWithData) {
assertHexEqual(actualBytes, pubkeyBytesHex);
}

TEST(TWCryptoBox, SecretKeyWithData) {
auto secretBytesHex = "dd87000d4805d6fbd89ae1352f5e4445648b79d5e901c92aebcb610e9be468e4";
auto secretBytes = DATA(secretBytesHex);

ASSERT_TRUE(TWCryptoBoxSecretKeyIsValid(secretBytes.get()));
const auto publicKey = WRAP(TWCryptoBoxSecretKey, TWCryptoBoxSecretKeyCreateWithData(secretBytes.get()));
const auto actualBytes = WRAPD(TWCryptoBoxSecretKeyData(publicKey.get()));
assertHexEqual(actualBytes, secretBytesHex);
}

TEST(TWCryptoBox, DecryptEasyError) {
auto otherPubkeyBytes = DATA("afccabc5b28a8a1fd1cd880516f9c854ae2498d0d1b978b53a59f38e4ae55747");

Expand Down

0 comments on commit a05c01a

Please sign in to comment.