Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TON]: Add CryptoBoxSecretKey FFIs to create from Bytes, get Bytes #3977

Merged
merged 5 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading