Closed heniotierra closed 5 years ago
Example runs fine for me, so you probably provided wrong sized key. It should have 32 bytes (in the example it decodes base64 encoded key from string to 32 key bytes). Note that key should be uniform random byte array, not password. If you want to use password, you should use key derivation function, such as https://github.com/dchest/scrypt-async-js/ to turn it into a 32-byte key.
Thank you for the quick reply. And I'm sorry, you're right, the example runs fine.
Actually what I'm doing is adapting the example to my need, but it seems strange to me that it raises an error because I followed the same exact flow. I'm not using a password.
I basically wrapped the example in a class. The difference is that I save the generated key in the file system for later use.
import { secretbox, randomBytes } from 'tweetnacl';
import {
decodeUTF8,
encodeUTF8,
encodeBase64,
decodeBase64
} from 'tweetnacl-util';
import * as fs from 'fs';
import * as path from 'path';
const naclKeyFilename = 'nacl.key';
export class Crypt {
private naclKey = '';
constructor(){
this.readKey();
}
private setNaclKey(key){
this.naclKey = key;
}
private readKey(){
const filePath = path.join(__dirname,`./${naclKeyFilename}`);
if(fs.existsSync(filePath)){
const data = fs.readFileSync(filePath);
this.setNaclKey(data);
}else{
const newKey = this.genKey();
this.setNaclKey(newKey);
fs.writeFileSync(filePath, newKey);
}
}
private newNonce() {
return randomBytes(secretbox.nonceLength);
}
private genKey(){
return encodeBase64(randomBytes(secretbox.keyLength));
}
encrypt (json) {
const key = this.naclKey;
console.log("chave:", key);
const keyUint8Array = decodeBase64(key);
const nonce = this.newNonce();
const messageUint8 = decodeUTF8(JSON.stringify(json));
const box = secretbox(messageUint8, nonce, keyUint8Array);
const fullMessage = new Uint8Array(nonce.length + box.length);
fullMessage.set(nonce);
fullMessage.set(box, nonce.length);
const base64FullMessage = encodeBase64(fullMessage);
return base64FullMessage;
};
decrypt (messageWithNonce) {
const key = this.naclKey;
const keyUint8Array = decodeBase64(key);
const messageWithNonceAsUint8Array = decodeBase64(messageWithNonce);
const nonce = messageWithNonceAsUint8Array.slice(0, secretbox.nonceLength);
const message = messageWithNonceAsUint8Array.slice(
secretbox.nonceLength,
messageWithNonce.length
);
const decrypted = secretbox.open(message, nonce, keyUint8Array);
if (!decrypted) {
throw new Error("Could not decrypt message");
}
const base64DecryptedMessage = encodeUTF8(decrypted);
return JSON.parse(base64DecryptedMessage);
}
}
I think the bug is that in readFileSync
you're not reading a string, but a buffer. If you replace it with const data = fs.readFileSync(filePath, { encoding: 'utf8' });
, it will return a string. Alternatively, remove all those encode/decodeBase64 and just use encoding: 'base64'
when saving and reading files or read/write binary files.
Anyway, this is not a tweetnacl problem, so you'll have to debug it yourself :)
Thanks! Using const data = fs.readFileSync(filePath, { encoding: 'utf8' });
works!
I'm getting the error below when I try to run the example at https://github.com/dchest/tweetnacl-js/wiki/Examples .
Can anybody help?