Skip to content

Commit

Permalink
Add fn to check that an AccountEntropyPool string is valid
Browse files Browse the repository at this point in the history
  • Loading branch information
akonradi-signal authored Dec 19, 2024
1 parent b115df3 commit a060aa6
Show file tree
Hide file tree
Showing 11 changed files with 67 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ public static String generate() {
return filterExceptions(() -> Native.AccountEntropyPool_Generate());
}

/**
* Checks whether a string can be used as an account entropy pool.
*
* @return <code>true</code> if the string is a structurally valid account entropy value.
*/
public static boolean isValid(String accountEntropyPool) {
return Native.AccountEntropyPool_IsValid(accountEntropyPool);
}

/**
* Derives an SVR key from the given account entropy pool.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ static MessageBackupKey makeMessageBackupKeyFromBackupId() {
static final String VALID_BACKUP_RESOURCE_NAME = "encryptedbackup.binproto.encrypted";
static final MessageBackup.Purpose BACKUP_PURPOSE = MessageBackup.Purpose.REMOTE_BACKUP;

@Test
public void AccountEntropyPoolValidity() {
assertFalse(AccountEntropyPool.isValid("invalid key"));
assertTrue(
AccountEntropyPool.isValid(
"0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqr"));
}

@Test
public void validBackupFile() throws IOException, ValidationError {
Supplier<InputStream> factory =
Expand Down
1 change: 1 addition & 0 deletions java/shared/java/org/signal/libsignal/internal/Native.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ private Native() {}
public static native byte[] AccountEntropyPool_DeriveBackupKey(String accountEntropy);
public static native byte[] AccountEntropyPool_DeriveSvrKey(String accountEntropy);
public static native String AccountEntropyPool_Generate();
public static native boolean AccountEntropyPool_IsValid(String accountEntropy);

public static native void Aes256Ctr32_Destroy(long handle);
public static native long Aes256Ctr32_New(byte[] key, byte[] nonce, int initialCtr) throws Exception;
Expand Down
1 change: 1 addition & 0 deletions node/Native.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export const enum LogLevel { Error = 1, Warn, Info, Debug, Trace }
export function AccountEntropyPool_DeriveBackupKey(accountEntropy: string): Buffer;
export function AccountEntropyPool_DeriveSvrKey(accountEntropy: string): Buffer;
export function AccountEntropyPool_Generate(): string;
export function AccountEntropyPool_IsValid(accountEntropy: string): boolean;
export function Aes256GcmSiv_Decrypt(aesGcmSiv: Wrapper<Aes256GcmSiv>, ctext: Buffer, nonce: Buffer, associatedData: Buffer): Buffer;
export function Aes256GcmSiv_Encrypt(aesGcmSivObj: Wrapper<Aes256GcmSiv>, ptext: Buffer, nonce: Buffer, associatedData: Buffer): Buffer;
export function Aes256GcmSiv_New(key: Buffer): Aes256GcmSiv;
Expand Down
9 changes: 9 additions & 0 deletions node/ts/AccountKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ export class AccountEntropyPool {
return Native.AccountEntropyPool_Generate();
}

/**
* Checks whether a string can be used as an account entropy pool.
*
* @returns `true` if the string is a structurally valid account entropy value.
*/
public static isValid(accountEntropyPool: string): boolean {
return Native.AccountEntropyPool_IsValid(accountEntropyPool);
}

/**
* Derives an SVR key from the given account entropy pool.
*
Expand Down
4 changes: 2 additions & 2 deletions node/ts/net.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,8 @@ class ConnectionInfoImpl
}
}

public toString() : string {
return Native.ChatConnectionInfo_description(this)
public toString(): string {
return Native.ChatConnectionInfo_description(this);
}
}

Expand Down
13 changes: 12 additions & 1 deletion node/ts/test/MessageBackupTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,22 @@ import { Uint8ArrayInputStream, ErrorInputStream } from './ioutil';
import * as fs from 'node:fs';
import * as path from 'node:path';
import { hkdf, LogLevel } from '..';
import { BackupKey } from '../AccountKeys';
import { AccountEntropyPool, BackupKey } from '../AccountKeys';
import { Readable } from 'node:stream';

util.initLogger(LogLevel.Trace);

describe('AccountEntropyPool', () => {
describe('isValid', () => {
assert.isFalse(AccountEntropyPool.isValid('invalid key'));
assert.isTrue(
AccountEntropyPool.isValid(
'0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqr'
)
);
});
});

describe('MessageBackup', () => {
const accountEntropy = 'm'.repeat(64);
const aci = Aci.fromUuidBytes(new Uint8Array(16).fill(0x11));
Expand Down
5 changes: 5 additions & 0 deletions rust/bridge/shared/src/account_keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ pub fn AccountEntropyPool_Generate() -> String {
AccountEntropyPool::generate(&mut rand::thread_rng()).to_string()
}

#[bridge_fn]
pub fn AccountEntropyPool_IsValid(account_entropy: String) -> bool {
AccountEntropyPool::from_str(&account_entropy).is_ok()
}

#[bridge_fn]
pub fn AccountEntropyPool_DeriveSvrKey(account_entropy: String) -> [u8; SVR_KEY_LEN] {
let entropy = AccountEntropyPool::from_str(&account_entropy)
Expand Down
11 changes: 11 additions & 0 deletions swift/Sources/LibSignalClient/AccountKeys.swift
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,17 @@ public enum AccountEntropyPool {
}
}

/// Checks whether a string can be used as an account entropy pool.
///
/// - returns: `true` if the string is a structurally valid account entropy value.
public static func isValid(_ accountEntropyPool: String) -> Bool {
failOnError {
try invokeFnReturningBool {
signal_account_entropy_pool_is_valid($0, accountEntropyPool)
}
}
}

/// Derives an SVR key from the given account entropy pool.
///
/// `accountEntropyPool` must be a **validated** account entropy pool;
Expand Down
2 changes: 2 additions & 0 deletions swift/Sources/SignalFfi/signal_ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -2035,6 +2035,8 @@ SignalFfiError *signal_pin_verify_local_hash(bool *out, const char *encoded_hash

SignalFfiError *signal_account_entropy_pool_generate(const char **out);

SignalFfiError *signal_account_entropy_pool_is_valid(bool *out, const char *account_entropy);

SignalFfiError *signal_account_entropy_pool_derive_svr_key(uint8_t (*out)[SignalSVR_KEY_LEN], const char *account_entropy);

SignalFfiError *signal_account_entropy_pool_derive_backup_key(uint8_t (*out)[SignalBACKUP_KEY_LEN], const char *account_entropy);
Expand Down
7 changes: 7 additions & 0 deletions swift/Tests/LibSignalClientTests/MessageBackupTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ class MessageBackupTests: TestCaseBase {
XCTAssertThrowsError(try backup.finalize())
}

func testAccountEntropyPoolValidity() {
XCTAssertFalse(AccountEntropyPool.isValid("invalid key"))
XCTAssertTrue(
AccountEntropyPool.isValid(
"0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqr"))
}

#if !os(iOS) || targetEnvironment(simulator)
func testComparableBackup() throws {
let bytes = readResource(forName: "canonical-backup.binproto")
Expand Down

0 comments on commit a060aa6

Please sign in to comment.