Skip to content
This repository has been archived by the owner on Jun 7, 2019. It is now read-only.

Commit

Permalink
🌱 Add better validation to decrypt passphrase
Browse files Browse the repository at this point in the history
Closes #688
  • Loading branch information
willclarktech committed Jul 13, 2018
1 parent 83de8e8 commit 95bf5b8
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 15 deletions.
12 changes: 7 additions & 5 deletions packages/lisk-cryptography/src/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,18 @@ export const bufferToBigNumberString = bigNumberBuffer =>
export const bufferToHex = buffer => Buffer.from(buffer).toString('hex');

const hexRegex = /^[0-9a-f]+/i;
export const hexToBuffer = hex => {
export const hexToBuffer = (hex, argumentName = 'Argument') => {
if (typeof hex !== 'string') {
throw new TypeError('Argument must be a string.');
throw new TypeError(`${argumentName} must be a string.`);
}
const matchedHex = (hex.match(hexRegex) || [])[0];
if (!matchedHex || matchedHex.length !== hex.length) {
throw new TypeError('Argument must be a valid hex string.');
throw new TypeError(`${argumentName} must be a valid hex string.`);
}
if (matchedHex.length % 2 !== 0) {
throw new TypeError('Argument must have a valid length of hex string.');
throw new TypeError(
`${argumentName} must have a valid length of hex string.`,
);
}
return Buffer.from(matchedHex, 'hex');
};
Expand Down Expand Up @@ -82,7 +84,7 @@ export const stringifyEncryptedPassphrase = encryptedPassphrase => {
iv: encryptedPassphrase.iv,
tag: encryptedPassphrase.tag,
version: encryptedPassphrase.version,
};
};
return querystring.stringify(objectToStringify);
};

Expand Down
29 changes: 21 additions & 8 deletions packages/lisk-cryptography/src/encrypt.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,23 +126,36 @@ const encryptAES256GCMWithPassword = (
};

const getTagBuffer = tag => {
const tagBuffer = hexToBuffer(tag);
const tagBuffer = hexToBuffer(tag, 'Tag');
if (tagBuffer.length !== 16) {
throw new Error('Tag must be 16 bytes.');
}
return tagBuffer;
};

const decryptAES256GCMWithPassword = (
{ iterations = PBKDF2_ITERATIONS, cipherText, iv, salt, tag },
password,
) => {
const decryptAES256GCMWithPassword = (encryptedPassphrase, password) => {
const {
iterations = PBKDF2_ITERATIONS,
cipherText,
iv,
salt,
tag,
} = encryptedPassphrase;

const tagBuffer = getTagBuffer(tag);
const key = getKeyFromPassword(password, hexToBuffer(salt), iterations);
const key = getKeyFromPassword(
password,
hexToBuffer(salt, 'Salt'),
iterations,
);

const decipher = crypto.createDecipheriv('aes-256-gcm', key, hexToBuffer(iv));
const decipher = crypto.createDecipheriv(
'aes-256-gcm',
key,
hexToBuffer(iv, 'IV'),
);
decipher.setAuthTag(tagBuffer);
const firstBlock = decipher.update(hexToBuffer(cipherText));
const firstBlock = decipher.update(hexToBuffer(cipherText, 'Cipher text'));
const decrypted = Buffer.concat([firstBlock, decipher.final()]);

return decrypted.toString();
Expand Down
20 changes: 19 additions & 1 deletion packages/lisk-cryptography/test/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ describe('convert', () => {
);
});

it('should throw an error for a non-string input with custom argument name', () => {
return expect(hexToBuffer.bind(null, {}, 'Custom')).to.throw(
'Custom must be a string.',
);
});

it('should throw TypeError with non hex string', () => {
return expect(hexToBuffer.bind(null, 'yKJj')).to.throw(
TypeError,
Expand Down Expand Up @@ -109,12 +115,24 @@ describe('convert', () => {
);
});

it('should throw TypeError with odd number of hex string', () => {
it('should throw an error for a non-hex string input with custom argument name', () => {
return expect(hexToBuffer.bind(null, 'yKJj', 'Custom')).to.throw(
'Custom must be a valid hex string.',
);
});

it('should throw TypeError with odd-length hex string', () => {
return expect(hexToBuffer.bind(null, 'c3a5c3a4c3b6a')).to.throw(
TypeError,
'Argument must have a valid length of hex string.',
);
});

it('should throw an error for an odd-length hex string input with custom argument name', () => {
return expect(hexToBuffer.bind(null, 'c3a5c3a4c3b6a', 'Custom')).to.throw(
'Custom must have a valid length of hex string.',
);
});
});

describe('#getFirstEightBytesReversed', () => {
Expand Down
46 changes: 45 additions & 1 deletion packages/lisk-cryptography/test/encrypt.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,50 @@ describe('encrypt', () => {
return expect(decrypted).to.be.equal(defaultPassphrase);
});

it('should inform the user if cipherText is missing', () => {
delete encryptedPassphrase.cipherText;
return expect(
decryptPassphraseWithPassword.bind(
null,
encryptedPassphrase,
defaultPassword,
),
).to.throw('Cipher text must be a string.');
});

it('should inform the user if iv is missing', () => {
delete encryptedPassphrase.iv;
return expect(
decryptPassphraseWithPassword.bind(
null,
encryptedPassphrase,
defaultPassword,
),
).to.throw('IV must be a string.');
});

it('should inform the user if salt is missing', () => {
delete encryptedPassphrase.salt;
return expect(
decryptPassphraseWithPassword.bind(
null,
encryptedPassphrase,
defaultPassword,
),
).to.throw('Salt must be a string.');
});

it('should inform the user if tag is missing', () => {
delete encryptedPassphrase.tag;
return expect(
decryptPassphraseWithPassword.bind(
null,
encryptedPassphrase,
defaultPassword,
),
).to.throw('Tag must be a string.');
});

it('should inform the user if the salt has been altered', () => {
encryptedPassphrase.salt = `00${encryptedPassphrase.salt.slice(2)}`;
return expect(
Expand Down Expand Up @@ -294,7 +338,7 @@ describe('encrypt', () => {
encryptedPassphrase,
defaultPassword,
),
).to.throw('Argument must be a valid hex string.');
).to.throw('Tag must be a valid hex string.');
});

it('should inform the user if the tag has been altered', () => {
Expand Down

0 comments on commit 95bf5b8

Please sign in to comment.