Bringing back js-sha3 to fix in-browser signing (#4063)

* Bring back Uint8Array sha3 support

* Added SHA3 test with HEX encoding

* Rename hex2Ascii => hexToAscii
Add tests or the api/util/format functions
Use js-sha3 for sha3 with hex encoding support

* Adding Uint8Array test

* Fixing Transaction import
This commit is contained in:
Tomasz Drwięga 2017-01-06 15:36:24 +01:00 committed by Jaco Greeff
parent 52d3633473
commit f6349187ef
9 changed files with 79 additions and 25 deletions

View File

@ -139,7 +139,6 @@
"blockies": "0.0.2",
"brace": "0.9.0",
"bytes": "2.4.0",
"crypto-js": "3.1.9-1",
"debounce": "1.0.0",
"es6-error": "4.0.0",
"es6-promise": "4.0.5",

View File

@ -20,15 +20,21 @@ export function bytesToHex (bytes) {
return '0x' + bytes.map((b) => ('0' + b.toString(16)).slice(-2)).join('');
}
export function hex2Ascii (_hex) {
const hex = /^(?:0x)?(.*)$/.exec(_hex.toString())[1];
export function hexToBytes (hex) {
const raw = toHex(hex).slice(2);
const bytes = [];
let str = '';
for (let i = 0; i < hex.length; i += 2) {
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
for (let i = 0; i < raw.length; i += 2) {
bytes.push(parseInt(raw.substr(i, 2), 16));
}
return bytes;
}
export function hexToAscii (hex) {
const bytes = hexToBytes(hex);
const str = bytes.map((byte) => String.fromCharCode(byte)).join('');
return str;
}

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { bytesToHex } from './format';
import { bytesToHex, hexToBytes, hexToAscii, bytesToAscii, asciiToHex } from './format';
describe('api/util/format', () => {
describe('bytesToHex', () => {
@ -26,4 +26,46 @@ describe('api/util/format', () => {
expect(bytesToHex([0, 15, 16])).to.equal('0x000f10');
});
});
describe('hexToBytes', () => {
it('correctly converts an empty string', () => {
expect(hexToBytes('')).to.deep.equal([]);
expect(hexToBytes('0x')).to.deep.equal([]);
});
it('correctly converts a non-empty string', () => {
expect(hexToBytes('0x000f10')).to.deep.equal([0, 15, 16]);
});
});
describe('asciiToHex', () => {
it('correctly converts an empty string', () => {
expect(asciiToHex('')).to.equal('0x');
});
it('correctly converts a non-empty string', () => {
expect(asciiToHex('abc')).to.equal('0x616263');
});
});
describe('hexToAscii', () => {
it('correctly converts an empty string', () => {
expect(hexToAscii('')).to.equal('');
expect(hexToAscii('0x')).to.equal('');
});
it('correctly converts a non-empty string', () => {
expect(hexToAscii('0x616263')).to.equal('abc');
});
});
describe('bytesToAscii', () => {
it('correctly converts an empty string', () => {
expect(bytesToAscii([])).to.equal('');
});
it('correctly converts a non-empty string', () => {
expect(bytesToAscii([97, 98, 99])).to.equal('abc');
});
});
});

View File

@ -16,7 +16,7 @@
import { isAddress as isAddressValid, toChecksumAddress } from '../../abi/util/address';
import { decodeCallData, decodeMethodInput, methodToAbi } from './decode';
import { bytesToHex, hex2Ascii, asciiToHex } from './format';
import { bytesToHex, hexToAscii, asciiToHex } from './format';
import { fromWei, toWei } from './wei';
import { sha3 } from './sha3';
import { isArray, isFunction, isHex, isInstanceOf, isString } from './types';
@ -30,7 +30,7 @@ export default {
isInstanceOf,
isString,
bytesToHex,
hex2Ascii,
hexToAscii,
asciiToHex,
createIdentityImg,
decodeCallData,

View File

@ -14,21 +14,17 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import CryptoJS from 'crypto-js';
import CryptoSha3 from 'crypto-js/sha3';
import { keccak_256 } from 'js-sha3'; // eslint-disable-line
import { hexToBytes } from './format';
export function sha3 (value, options) {
if (options && options.encoding === 'hex') {
if (value.length > 2 && value.substr(0, 2) === '0x') {
value = value.substr(2);
const bytes = hexToBytes(value);
return sha3(bytes);
}
value = CryptoJS.enc.Hex.parse(value);
}
const hash = CryptoSha3(value, {
outputLength: 256
}).toString();
const hash = keccak_256(value);
return `0x${hash}`;
}

View File

@ -21,5 +21,16 @@ describe('api/util/sha3', () => {
it('constructs a correct sha3 value', () => {
expect(sha3('jacogr')).to.equal('0x2f4ff4b5a87abbd2edfed699db48a97744e028c7f7ce36444d40d29d792aa4dc');
});
it('constructs a correct sha3 encoded as hex', () => {
const key = '000000000000000000000000391694e7e0b0cce554cb130d723a9d27458f9298' + '0000000000000000000000000000000000000000000000000000000000000001';
expect(sha3(key, { encoding: 'hex' })).to.equal('0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9');
expect(sha3(`0x${key}`, { encoding: 'hex' })).to.equal('0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9');
});
it('constructs a correct sha3 from Uint8Array', () => {
expect(sha3('01020304', { encoding: 'hex' })).to.equal('0xa6885b3731702da62e8e4a8f584ac46a7f6822f4e2ba50fba902f67b1588d23b');
expect(sha3(Uint8Array.from([1, 2, 3, 4]))).to.equal('0xa6885b3731702da62e8e4a8f584ac46a7f6822f4e2ba50fba902f67b1588d23b');
});
});
});

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import { bytesToHex, hex2Ascii } from '~/api/util/format';
import { bytesToHex, hexToAscii } from '~/api/util/format';
import ABI from './abi/certifier.json';
@ -62,7 +62,7 @@ export default class BadgeReg {
name = bytesToHex(name);
name = name === ZERO32
? null
: hex2Ascii(name);
: hexToAscii(name);
return this.fetchMeta(id)
.then(({ title, icon }) => {
@ -84,7 +84,7 @@ export default class BadgeReg {
})
.then(([ title, icon ]) => {
title = bytesToHex(title);
title = title === ZERO32 ? null : hex2Ascii(title);
title = title === ZERO32 ? null : hexToAscii(title);
if (bytesToHex(icon) === ZERO32) {
icon = null;

View File

@ -167,7 +167,7 @@ class MethodDecoding extends Component {
getAscii () {
const { api } = this.context;
const { transaction } = this.props;
const ascii = api.util.hex2Ascii(transaction.input || transaction.data);
const ascii = api.util.hexToAscii(transaction.input || transaction.data);
return { value: ascii, valid: ASCII_INPUT.test(ascii) };
}

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import scrypt from 'scryptsy';
import Transaction from 'ethereumjs-tx';
import * as Transaction from 'ethereumjs-tx';
import { pbkdf2Sync } from 'crypto';
import { createDecipheriv } from 'browserify-aes';