-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add TLV / LV / KLV Decoding Operation #351
Changes from 4 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/** | ||
* @author gchq77703 [] | ||
* @copyright Crown Copyright 2018 | ||
* @license Apache-2.0 | ||
*/ | ||
|
||
const defaults = { | ||
location: 0, | ||
bytesInLength: 1, | ||
basicEncodingRules: false | ||
}; | ||
|
||
/** | ||
* Length Value library | ||
*/ | ||
export default class LengthValue { | ||
|
||
/** | ||
* LengthValue constructor | ||
*/ | ||
constructor(input, options) { | ||
this.input = input; | ||
Object.assign(this, defaults, options); | ||
} | ||
|
||
/** | ||
* @returns {Number} | ||
*/ | ||
getLength() { | ||
if (this.basicEncodingRules) { | ||
const bit = this.input[this.location]; | ||
if (bit & 0x80) { | ||
this.bytesInLength = bit & ~0x80; | ||
} else { | ||
this.location++; | ||
return bit & ~0x80; | ||
} | ||
} | ||
|
||
let length = 0; | ||
|
||
for (let i = 0; i < this.bytesInLength; i++) { | ||
length += this.input[this.location] * Math.pow(Math.pow(2, 8), i); | ||
this.location++; | ||
} | ||
|
||
return length; | ||
} | ||
|
||
/** | ||
* @param {Number} length | ||
* @returns {Number[]} | ||
*/ | ||
getValue(length) { | ||
const value = []; | ||
|
||
for (let i = 0; i < length; i++) { | ||
value.push(this.input[this.location]); | ||
this.location++; | ||
} | ||
|
||
return value; | ||
} | ||
|
||
/** | ||
* @returns {Boolean} | ||
*/ | ||
atEnd() { | ||
return this.input.length <= this.location; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/** | ||
* @author gchq77703 [] | ||
* @copyright Crown Copyright 2018 | ||
* @license Apache-2.0 | ||
*/ | ||
|
||
import Operation from "../Operation"; | ||
import LengthValue from "../lib/LengthValue"; | ||
|
||
/** | ||
* From Length Value operation | ||
*/ | ||
class FromLengthValue extends Operation { | ||
|
||
/** | ||
* FromLengthValue constructor | ||
*/ | ||
constructor() { | ||
super(); | ||
|
||
this.name = "From Length Value"; | ||
this.module = "Default"; | ||
this.description = "Converts a Length-Value (LV) encoded string into a JSON object. Can optionally include a <code>Key</code> / <code>Type</code> entry."; | ||
this.infoURL = ""; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a link to the appropriate wiki page |
||
this.inputType = "byteArray"; | ||
this.outputType = "JSON"; | ||
this.args = [ | ||
{ | ||
name: "Bytes in Key Value", | ||
type: "populateOption", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the wrong argument type to use. Take a look here for a description of each of the ingredient types: https://github.com/gchq/CyberChef/wiki/Adding-a-new-operation#data-types |
||
value: [ | ||
{ | ||
name: "0 Bytes (No Key)", | ||
value: "0" | ||
}, | ||
{ | ||
name: "1 Byte", | ||
value: "1" | ||
}, | ||
{ | ||
name: "2 Bytes", | ||
value: "2" | ||
}, | ||
{ | ||
name: "4 Bytes", | ||
value: "4" | ||
} | ||
] | ||
}, | ||
{ | ||
name: "Bytes in Length Value", | ||
type: "populateOption", | ||
value: [ | ||
{ | ||
name: "1 Byte", | ||
value: "1" | ||
}, | ||
{ | ||
name: "2 Bytes", | ||
value: "2" | ||
}, | ||
{ | ||
name: "4 Bytes", | ||
value: "4" | ||
} | ||
] | ||
}, | ||
{ | ||
name: "Use Basic Encoding Rules", | ||
type: "boolean" | ||
} | ||
]; | ||
} | ||
|
||
/** | ||
* @param {byteArray} input | ||
* @param {Object[]} args | ||
* @returns {string} | ||
*/ | ||
run(input, args) { | ||
const bytesInKey = parseInt(args[0].split(" ")[0], 10); | ||
const bytesInLength = parseInt(args[1].split(" ")[0], 10); | ||
const basicEncodingRules = args[2]; | ||
|
||
const lv = new LengthValue(input, { bytesInLength, basicEncodingRules }); | ||
|
||
const data = []; | ||
|
||
while (!lv.atEnd()) { | ||
const key = bytesInKey ? lv.getValue(bytesInKey) : undefined; | ||
const length = lv.getLength(); | ||
const value = lv.getValue(length); | ||
|
||
data.push({ key, length, value }); | ||
} | ||
|
||
return data; | ||
} | ||
|
||
} | ||
|
||
export default FromLengthValue; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/** | ||
* Length Value Decoder tests. | ||
* | ||
* @author gchq77703 [] | ||
* @copyright Crown Copyright 2018 | ||
* @license Apache-2.0 | ||
*/ | ||
|
||
import TestRegister from "../../TestRegister"; | ||
|
||
TestRegister.addTests([ | ||
{ | ||
name: "KeyValue", | ||
input: [5, 72, 111, 117, 115, 101, 4, 114, 111, 111, 109, 4, 100, 111, 111, 114], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can see your logic here and it should probably be possible to do, but as it stands, tests expect all input and output to be a string, in the same way that the web app takes all input as a string and returns all output as a string. The data will be converted to a byteArray automatically by CyberChef before it is passed to the operation. In this case, you probably want to pass in |
||
expectedOutput: [{"key": [25], "length": 5, "value": [72, 111, 117, 115, 101]}, {"key": [73], "length": 4, "value": [114, 111, 111, 109]}, {"key": [41], "length": 4, "value": [100, 111, 111, 114]}], | ||
recipeConfig: [ | ||
{ | ||
"op": "Length Value Decoder", | ||
"args": ["0 Bytes (No Key)", "1 Byte", false] | ||
} | ||
] | ||
}, | ||
]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rename this to something like 'LV Decode'. Then we can have an 'LV Encode' operation that does the opposite.