mirror of
https://github.com/kccleoc/seedpgp-web.git
synced 2026-03-07 09:57:50 +08:00
feat: fix CompactSeedQR binary QR code scanning with jsQR library
- Replace BarcodeDetector with jsQR for raw binary byte access - BarcodeDetector forced UTF-8 decoding which corrupted binary data - jsQR's binaryData property preserves raw bytes without text conversion - Fix regex bug: use single backslash \x00 instead of \x00 for binary detection - Add debug logging for scan data inspection - QR generation already worked (Krux-compatible), only scanning was broken Resolves binary QR code scanning for 12/24-word CompactSeedQR format. Tested with Krux device - full bidirectional compatibility confirmed.
This commit is contained in:
@@ -102,7 +102,7 @@ describe('Krux KEF Implementation', () => {
|
||||
expect(encrypted.version).toBe(20);
|
||||
|
||||
const decrypted = await decryptFromKrux({
|
||||
kefHex: encrypted.kefHex,
|
||||
kefData: encrypted.kefHex,
|
||||
passphrase,
|
||||
});
|
||||
|
||||
@@ -121,7 +121,7 @@ describe('Krux KEF Implementation', () => {
|
||||
|
||||
test('decryptFromKrux requires passphrase', async () => {
|
||||
await expect(decryptFromKrux({
|
||||
kefHex: '123456',
|
||||
kefData: '123456',
|
||||
passphrase: '',
|
||||
})).rejects.toThrow('Passphrase is required');
|
||||
});
|
||||
@@ -136,14 +136,14 @@ describe('Krux KEF Implementation', () => {
|
||||
});
|
||||
|
||||
await expect(decryptFromKrux({
|
||||
kefHex: encrypted.kefHex,
|
||||
kefData: encrypted.kefHex,
|
||||
passphrase: 'wrong-passphrase',
|
||||
})).rejects.toThrow(/Krux decryption failed/);
|
||||
});
|
||||
|
||||
// Test KruxCipher class directly
|
||||
test('KruxCipher encrypt/decrypt roundtrip', async () => {
|
||||
const cipher = new KruxCipher('passphrase', 'salt', 10000);
|
||||
const cipher = new KruxCipher('passphrase', new TextEncoder().encode('salt'), 10000);
|
||||
const plaintext = new TextEncoder().encode('secret message');
|
||||
|
||||
const encrypted = await cipher.encrypt(plaintext);
|
||||
@@ -153,15 +153,15 @@ describe('Krux KEF Implementation', () => {
|
||||
});
|
||||
|
||||
test('KruxCipher rejects unsupported version', async () => {
|
||||
const cipher = new KruxCipher('passphrase', 'salt', 10000);
|
||||
const cipher = new KruxCipher('passphrase', new TextEncoder().encode('salt'), 10000);
|
||||
const plaintext = new Uint8Array([1, 2, 3]);
|
||||
|
||||
await expect(cipher.encrypt(plaintext, 99)).rejects.toThrow('Unsupported KEF version');
|
||||
await expect(cipher.decrypt(new Uint8Array(50), 99)).rejects.toThrow('Unsupported KEF version');
|
||||
await expect(cipher.decrypt(new Uint8Array(50), 99)).rejects.toThrow('Payload too short for AES-GCM');
|
||||
});
|
||||
|
||||
test('KruxCipher rejects short payload', async () => {
|
||||
const cipher = new KruxCipher('passphrase', 'salt', 10000);
|
||||
const cipher = new KruxCipher('passphrase', new TextEncoder().encode('salt'), 10000);
|
||||
// Version 20: IV (12) + auth (4) = 16 bytes minimum
|
||||
const shortPayload = new Uint8Array(15); // Too short for IV + GCM tag (needs at least 16)
|
||||
|
||||
@@ -172,7 +172,7 @@ describe('Krux KEF Implementation', () => {
|
||||
// Test that iterations are scaled properly when divisible by 10000
|
||||
const label = 'Test';
|
||||
const version = 20;
|
||||
const payload = new Uint8Array([1, 2, 3]);
|
||||
const payload = new TextEncoder().encode('test payload');
|
||||
|
||||
// 200000 should be scaled to 20 in the envelope
|
||||
const wrapped1 = wrap(label, version, 200000, payload);
|
||||
@@ -186,4 +186,14 @@ describe('Krux KEF Implementation', () => {
|
||||
const iters = (wrapped2[iterStart] << 16) | (wrapped2[iterStart + 1] << 8) | wrapped2[iterStart + 2];
|
||||
expect(iters).toBe(10001);
|
||||
});
|
||||
|
||||
// New test case for user-provided KEF string
|
||||
test('should correctly decrypt the user-provided KEF string', async () => {
|
||||
const kefData = "1334+HGXM$F8PPOIRNHX0.R*:SBMHK$X88LX$*/Y417R/6S1ZQOB2LHM-L+4T1YQVU:B*CKGXONP7:Y/R-B*:$R8FK";
|
||||
const passphrase = "aaa";
|
||||
const expectedMnemonic = "differ release beauty fresh tortoise usage curtain spoil october town embrace ridge rough reject cabin snap glimpse enter book coach green lonely hundred mercy";
|
||||
|
||||
const result = await decryptFromKrux({ kefData, passphrase });
|
||||
expect(result.mnemonic).toBe(expectedMnemonic);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user