mirror of
https://github.com/gchq/CyberChef.git
synced 2025-04-28 02:36:16 -04:00
Hotfix: Fixed a bug where if a private or public key ended with a0 or other whitespace byte, the validatePrivate or Public Key function in Bitcoin.mjs would strip that byte. In addition added a Public Key To TRX Address Operation.
This commit is contained in:
parent
e96e31cd52
commit
f7ebae4e88
5 changed files with 202 additions and 24 deletions
|
@ -355,7 +355,8 @@
|
|||
"Seed To Master Key",
|
||||
"Decrypt Keystore File",
|
||||
"BIP32Derive",
|
||||
"Public Key To ETH Style Address"
|
||||
"Public Key To ETH Style Address",
|
||||
"Public Key To TRX Style Address"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -28,7 +28,7 @@ function validateLengths(input, allowableLengths) {
|
|||
*/
|
||||
function isHex(input) {
|
||||
const re = /^[0-9A-Fa-f]{2,}$/g;
|
||||
return re.test(input);
|
||||
return re.test(input) && input.length %2 === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,14 +49,13 @@ function isValidBytes(input) {
|
|||
* @param {*} input
|
||||
*/
|
||||
export function validatePrivateKey(input) {
|
||||
const curInput = input.trim();
|
||||
if (!validateLengths(curInput, [32, 64])) {
|
||||
return "Invalid length. We want either 32 or 64 but we got: " + curInput.length;
|
||||
if (!validateLengths(input, [32, 64])) {
|
||||
return "Invalid length. We want either 32 or 64 but we got: " + input.length;
|
||||
}
|
||||
if (curInput.length === 64 && !isHex(curInput)) {
|
||||
if (input.length === 64 && !isHex(input)) {
|
||||
return "We have a string of length 64, but not valid hex. Cannot be interpreted as a private key.";
|
||||
}
|
||||
if (curInput.length === 32 && !isValidBytes(curInput)) {
|
||||
if (input.length === 32 && !isValidBytes(input)) {
|
||||
return "We have a string of length 32 but cannot cannot be interpreted as valid bytes.";
|
||||
}
|
||||
return "";
|
||||
|
@ -70,31 +69,30 @@ export function validatePrivateKey(input) {
|
|||
* @param {*} input
|
||||
*/
|
||||
export function validatePublicKey(input) {
|
||||
const curInput = input.trim();
|
||||
if (!validateLengths(curInput, [33, 65, 66, 130])) {
|
||||
return "Invalid length. We want either 33, 65 (if bytes) or 66, 130 (if hex) but we got: " + curInput.length;
|
||||
if (!validateLengths(input, [33, 65, 66, 130])) {
|
||||
return "Invalid length. We want either 33, 65 (if bytes) or 66, 130 (if hex) but we got: " + input.length;
|
||||
}
|
||||
if (isHex(curInput)) {
|
||||
if (!validateLengths(curInput, [66, 130])) {
|
||||
return "We have a hex string, but its length is wrong. We want 66, 130 but we got: " + curInput.length;
|
||||
if (isHex(input)) {
|
||||
if (!validateLengths(input, [66, 130])) {
|
||||
return "We have a hex string, but its length is wrong. We want 66, 130 but we got: " + input.length;
|
||||
}
|
||||
if (curInput.length === 66 && (curInput.slice(0, 2) !== "02" && curInput.slice(0, 2) !== "03")) {
|
||||
return "We have a valid hex string, of reasonable length, (66) but doesn't start with the right value. Correct values are 02, or 03 but we have: " + curInput.slice(0, 2);
|
||||
if (input.length === 66 && (input.slice(0, 2) !== "02" && input.slice(0, 2) !== "03")) {
|
||||
return "We have a valid hex string, of reasonable length, (66) but doesn't start with the right value. Correct values are 02, or 03 but we have: " + input.slice(0, 2);
|
||||
}
|
||||
if (curInput.length === 130 && curInput.slice(0, 2) !== "04") {
|
||||
return "We have a valid hex string of reasonable length, (130) but doesn't start with the right value. Correct values are 04 but we have: " + curInput.slice(0, 2);
|
||||
if (input.length === 130 && input.slice(0, 2) !== "04") {
|
||||
return "We have a valid hex string of reasonable length, (130) but doesn't start with the right value. Correct values are 04 but we have: " + input.slice(0, 2);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
if (isValidBytes(curInput)) {
|
||||
if (!validateLengths(curInput, [33, 65])) {
|
||||
return "We have a byte string, but its length is wrong. We want 33 or 65 but we got: " + curInput.length;
|
||||
if (isValidBytes(input)) {
|
||||
if (!validateLengths(input, [33, 65])) {
|
||||
return "We have a byte string, but its length is wrong. We want 33 or 65 but we got: " + input.length;
|
||||
}
|
||||
if (curInput.length === 33 && toHex(curInput[0]) !== "02" && toHex(curInput[0]) !== "03") {
|
||||
return "We have a valid byte string, of reasonable length, (33) but doesn't start with the right value. Correct values are 02, or 03 but we have: " + toHex(curInput[0]) ;
|
||||
if (input.length === 33 && toHex(input[0]) !== "02" && toHex(input[0]) !== "03") {
|
||||
return "We have a valid byte string, of reasonable length, (33) but doesn't start with the right value. Correct values are 02, or 03 but we have: " + toHex(input[0]) ;
|
||||
}
|
||||
if (curInput.length === 65 && toHex(curInput[0]) !== "04") {
|
||||
return "We have a valid byte string, of reasonable length, (65) but doesn't start with the right value. Correct value is 04 but we have: " + toHex(curInput[0]);
|
||||
if (input.length === 65 && toHex(input[0]) !== "04") {
|
||||
return "We have a valid byte string, of reasonable length, (65) but doesn't start with the right value. Correct value is 04 but we have: " + toHex(input[0]);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
|
81
src/core/operations/PublicKeyToTRXStyleAddress.mjs
Normal file
81
src/core/operations/PublicKeyToTRXStyleAddress.mjs
Normal file
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* @author dgoldenberg [virtualcurrency@mitre.org]
|
||||
* @copyright Crown Copyright 2024
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import {makeSureIsBytes, validatePublicKey, base58Encode, doubleSHA} from "../lib/Bitcoin.mjs";
|
||||
import { fromArrayBuffer } from "crypto-api/src/encoder/array-buffer.mjs";
|
||||
import {toHex} from "crypto-api/src/encoder/hex.mjs";
|
||||
import JSSHA3 from "js-sha3";
|
||||
import Utils from "../Utils.mjs";
|
||||
import ec from "elliptic";
|
||||
|
||||
/**
|
||||
* Turns a public key into an ETH address.
|
||||
* @param {*} input Input, a public key in hex or bytes.
|
||||
*/
|
||||
function pubKeyToTRXAddress(input) {
|
||||
// Ethereum addresses require uncompressed public keys.
|
||||
// We convert if the public key is compressed.
|
||||
let curKey = makeSureIsBytes(input);
|
||||
if (curKey[0] !== 0x04 || curKey.length !== 65) {
|
||||
const ecContext = ec.ec("secp256k1");
|
||||
const thisKey = ecContext.keyFromPublic(curKey);
|
||||
curKey = thisKey.getPublic(false, "hex");
|
||||
}
|
||||
const algo = JSSHA3.keccak256;
|
||||
// We need to redo the hex-> bytes transformation here because Javascript is silly.
|
||||
// sometimes what is desired is an array of ints.
|
||||
// Other times a string
|
||||
// Here, the Keccak algorithm seems to want an array of ints. (sigh)
|
||||
const result = algo(Utils.convertToByteArray(curKey, "hex").slice(1,));
|
||||
const unencodedAddress = result.slice(-40);
|
||||
const checksumHash = toHex(doubleSHA(fromArrayBuffer(Utils.convertToByteArray("41" + unencodedAddress, "hex"))));
|
||||
const finalString = "41" + unencodedAddress + checksumHash.slice(0, 8);
|
||||
const address = base58Encode(Utils.convertToByteArray(finalString, "hex"));
|
||||
return address;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Public Key To TRX Style Address operation
|
||||
*/
|
||||
class PublicKeyToTRXStyleAddress extends Operation {
|
||||
|
||||
/**
|
||||
* PublicKeyToTRXStyleAddress constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Public Key To TRX Style Address";
|
||||
this.module = "Default";
|
||||
this.description = "Converts a public key, (33 bytes beginning with 02 or 03 for compressed or 65 bytes beginning with 04) to a TRX style address. This involves hashing the public key using keccack-256 like Ethereum, but encoding the result using base58 encoding. ";
|
||||
this.infoURL = "https://developers.tron.network/docs/account";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
// We check if input is blank.
|
||||
// If its blank or just whitespace, we don't need to bother dealing with it.
|
||||
if (input.trim().length === 0) {
|
||||
return "";
|
||||
}
|
||||
if (validatePublicKey(input) !== "") {
|
||||
return validatePublicKey(input);
|
||||
}
|
||||
return pubKeyToTRXAddress(input);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PublicKeyToTRXStyleAddress;
|
|
@ -183,6 +183,7 @@ import "./tests/WIFToPrivateKey.mjs";
|
|||
import "./tests/SeedphraseToSeed.mjs";
|
||||
import "./tests/DeserializeExtendedKey.mjs";
|
||||
import "./tests/PublicKeyToETHStyleAddress.mjs";
|
||||
import "./tests/PublicKeyToTRXStyleAddress.mjs";
|
||||
import "./tests/GetAllCasings.mjs";
|
||||
import "./tests/SIGABA.mjs";
|
||||
import "./tests/ELFInfo.mjs";
|
||||
|
|
97
tests/operations/tests/PublicKeyToTRXStyleAddress.mjs
Normal file
97
tests/operations/tests/PublicKeyToTRXStyleAddress.mjs
Normal file
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* Public Key to TRX Style Address Cryptocurrency Address tests.
|
||||
*
|
||||
* @author dgoldenberg [virtualcurrency@mitre.org]
|
||||
* @copyright MITRE 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Public Key To TRX Style Address",
|
||||
input: "04187ac6bc2723630c936e363b826de17dac62382e3bbfabf306ad5f55cc79538783889fe32946b52092dad24c56893d522413d67e62b28f6c54f14821367a9edc",
|
||||
expectedOutput: "THV2shRZn4cam7aQreAg9aixfk2sTcho6r",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Public Key To TRX Style Address",
|
||||
"args": []
|
||||
},
|
||||
],
|
||||
|
||||
},
|
||||
{
|
||||
name: "Public Key To TRX Style Address Compressed Key",
|
||||
input: "02d1b5855d3f99c4449eb7af576bec1b9bc0bf0769446820686d2de5c47c13b1a0",
|
||||
expectedOutput: "TQS4NjvDN4TxcZd8LwD1eAKv9y4vSVkDW2",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Public Key To TRX Style Address",
|
||||
"args": []
|
||||
},
|
||||
],
|
||||
|
||||
},
|
||||
{
|
||||
name: "Public Key to ETH Style Address: Compressed Key 2",
|
||||
input: "03a85e8f6fc71898b5c3347decd2c0bba8abb99393c8358fcf0bca72e4c7d68514",
|
||||
expectedOutput: "TXBP2ebjZsnDEL9X5xCZSZZ6FC3Vppccv4",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Public Key To TRX Style Address",
|
||||
"args": []
|
||||
},
|
||||
],
|
||||
|
||||
},
|
||||
{
|
||||
name: "Public Key to ETH Style Address: Compressed Key 2 (From Hex)",
|
||||
input: "03a85e8f6fc71898b5c3347decd2c0bba8abb99393c8358fcf0bca72e4c7d68514",
|
||||
expectedOutput: "TXBP2ebjZsnDEL9X5xCZSZZ6FC3Vppccv4",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "Public Key To TRX Style Address",
|
||||
"args": [],
|
||||
},
|
||||
],
|
||||
|
||||
},
|
||||
{
|
||||
name: "Public Key to TRX Style Address: Compressed Key (From Hex)",
|
||||
input: "02d1b5855d3f99c4449eb7af576bec1b9bc0bf0769446820686d2de5c47c13b1a0",
|
||||
expectedOutput: "TQS4NjvDN4TxcZd8LwD1eAKv9y4vSVkDW2",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "Public Key To TRX Style Address",
|
||||
"args": []
|
||||
},
|
||||
],
|
||||
|
||||
},
|
||||
{
|
||||
name: "Public Key To TRX Style Address (From Hex)",
|
||||
input: "04187ac6bc2723630c936e363b826de17dac62382e3bbfabf306ad5f55cc79538783889fe32946b52092dad24c56893d522413d67e62b28f6c54f14821367a9edc",
|
||||
expectedOutput: "THV2shRZn4cam7aQreAg9aixfk2sTcho6r",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Auto"]
|
||||
},
|
||||
{
|
||||
"op": "Public Key To TRX Style Address",
|
||||
"args": []
|
||||
},
|
||||
],
|
||||
|
||||
},
|
||||
]);
|
Loading…
Add table
Add a link
Reference in a new issue