Conditionally parsing an array based on previous elements with nom - parsing

I need to parse an array of 32 bit ints (little endian), from an array of u8s, however the next int only exists if the 31st bit of the current int is set. If the rest don't exist then the rest of the array should be set to zeroes. I'm not sure how to go about conditionally parsing the next element.
Lets say the field is 4 bytes long. Then the result of the parse_field function would be that the 4 bytes would be parsed with le_u32, and that would be the first element in the [u32; 8] array. If however, this field's 31st bit is set. Then there exists another 4 bytes that is also like this field and it goes in the next element in the array. If it is not set then the function must return, the array with the rest of the elements set to zero. And this continue for each existing field.
For example for the following input:
0x8000000a
0x8000000b
...
You would get [0x8000000a, 0x8000000b, 0, 0, 0, 0, 0, 0]
But if the input is
0x8000000a
0x8000000b
0x8000000c
0x8000000d
0x8000000e
....
Then you would get [0x8000000a, 0x8000000b, 0x8000000c, 0x8000000d, 0x8000000e, 0, 0, 0]
extern crate nom;
use nom::*;
#[derive(Clone, Copy, Debug)]
struct Derp {
field: [u32; 8]
}
named!(parse_field<[u32; 8]>,
// what do I do here
);
named!(parse_derp<Derp>,
do_parse!(
field: parse_field >>
(Derp {
field: field
})
)
);
fn main() {
let temp = [0x0a, 0x00, 0x00, 0x80, 0x0b, 0x00, 0x00, 0x80];
println!("{:?}", parse_derp(&temp));
}
Also is it possibly better to use a Vec here?

Here is a parser that matches the last u32 of your input:
named!(last_u32<u32>,
verify!(le_u32, |n:u32| (n & 0b1) != 0) // Matches iff the 31st bit is set
);
you can then use it like this:
named!(parse_field<Vec<u32>>,
map!(
many_till!(le_u32, last_u32),
|(mut v,n)| { v.push(n); v } // Add the last u32 to the vector
)
);

Related

Reversing Of Intergers(take Input from user and Reverse it)

I want To build a Program in which i want Multiple inputs in integers and Reverse it .. how Can I Do that in Dart?
I tried of strings But Don't Know About Integers
You can do something like this:
import 'dart:io';
void main() {
print('Input integers (q to stop):');
final integers = <int>[];
while (true) {
// Reads input from the user.
final input = stdin.readLineSync()!;
// Check to see if the user is done inputting numbers.
if (input == 'q') {
break;
}
// Try to convert the String to an int. If input isn't a
// valid integer, int.tryParse(input) == null.
final integer = int.tryParse(input);
if (integer != null) {
integers.add(integer);
}
}
print('Original order: $integers');
// Reversing a List in Dart is simple: just call integers.reverse
// to get an Iterable with the elements of integers in reversed order.
// Calling integers.reverse.toList() will convert the Iterable to a List
// so it's possible to print the entire list at once.
print('Reversed order: ${integers.reversed.toList()}');
}
Example:
Input integers (q to stop):
1
2
3
r
4
5
q
Original order: [1, 2, 3, 4, 5]
Reversed order: [5, 4, 3, 2, 1]

Dart fill ByteData with List<int>

List<int> l = [ 1, 2, 3, 4 ];
var b = ByteData(10);
May I know what is the easiest way to fill b (position 4 ~ 7) with data from l.
I can certainly iterate through l and then fill b one by one. But this is just part of a larger solution. So I hope there is a simpler way (for easy maintenance in future).
ByteData represent an area of memory counted in bytes but does not tell us anything how we want to represent the data inside this block of memory.
Normally, we would use one of the specific data types from dart:typed_data like e.g. Uint8List, Int8List, Uint16List and so on which have a lot more functionality.
But you can easily get the same by making a view over your ByteData. In this example I guess you want to insert your numbers as Uint8:
import 'dart:typed_data';
void main() {
List<int> l = [ 1, 2, 3, 4 ];
var b = ByteData(10);
var uInt8ListViewOverB = b.buffer.asUint8List();
uInt8ListViewOverB.setAll(4, l);
print(uInt8ListViewOverB); // [0, 0, 0, 0, 1, 2, 3, 4, 0, 0]
}
I recommend reading the documentation for the different methods on ByteBuffer (returned by buffer). You can e.g. make subview of a limited part of your ByteData if your ByteData needs to contain different types of data:
https://api.dart.dev/stable/2.15.0/dart-typed_data/ByteBuffer/asUint8List.html

Equivalent for Java System.arraycopy in Dart?

How do I convert the below java code to equivalent dart.
private static final byte[] mIdBytes = new byte[]{(byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x7E};
byte[] data;
System.arraycopy(mIdBytes, 2, data, 0, 4);
Is there any Dart method that does a similar kind of operation?
I was looking into this:
https://pub.dev/documentation/ckb_dart_sdk/latest/ckb-utils_number/arrayCopy.html
To match Java's System.arrayCopy(source, sourceOffset, target, targetOffset, length)
you should use
target.setRange(targetOffset, targetOffset + length, source, sourceOffset);
This is more efficient than using List.copyRange for some lists, for example copying between typed-data lists with the same element size (like two Uint8Lists).
Well, I found the way to do it.
you can just use
List.copyRange(data, 0, mIdBytes, 2);
This is a workaround I kinda found to be done in your case. This is called sublist(), this method will take the start index, and an end index.
IDEA:
Use sublist(), and copy the elements to be started from, that sourcePos = you_pos
Source array will be used like sourceArray.sublist(startIndext, endIndex)
The destination array will be initialized with the value using sublist()
Till what length the item should be added would be mentioned in the end index+2, since it will ignore the last item, and copy till the index-1
FINAL CODE
void main() {
List<int> source = [1, 2, 3, 4, 5, 6];
List<int> target = [];
int startPos = 1;
int length = 4;
// to ensure the length doesn't exceeds limit
// length+2 because, it targets on the end index, that is 4 in source list
// but the end result should be length+2 to contain a length of 5 items
if(length+1 <= source.length-1){
target = source.sublist(startPos, length+2);
print(target);
}else{
print('Cannot copy items till $length: index out of bound');
}
}
//OUTPUT
[2, 3, 4, 5, 6]

Why might '_Uint8ArrayView' be returned to a Dart command line client's websocket onData handler?

I have a command line Dart script client interacting over a [dart:io] websocket with a Jetty server. I've implemented a custom message subprotocol that uses reflection (both sides) to exchange Dart objects with Java objects in Jetty using binary encoding. PODO -> Uint8List -> wire -> ByteBufer -> POJO (and in reverse for the return trip). The local round trip unit tests execute correctly on either side (i.e. PODO -> Uint8List -> PODO; POJO -> ByteBuffer -> POJO). I've tested the connection with a different service endpoint using a series of simple 'string' exchanges. The transmission from Dart to Jetty works but the response data, although correctly received, produces an odd type that I don't understand and which the decoder doesn't understand as either a Uint8List, ByteBuffer, etc.
Although I can't easily distill this into a small example, here is the relevant code and some output:
Dart Client:
WebSocket.connect(url).then((WebSocket socket) {
_log.finer('connected');
_websocket = socket
..listen(_onResponse, onError: (e, StackTrace st) => print('Session error: $e; $st'));
...
}
_onResponse(data) {
print('response raw data: $data');
InstanceMirror im = reflect(data);
print('instance: $im');
...
decode(data)
}
decode(Uint8List data) {
var b = data.buffer;
ByteData bd = new ByteData.view(b);
int offset = 0;
const ENDIANNESS = Endianness.LITTLE_ENDIAN;
int msgLength = bd.getInt32(offset, ENDIANNESS); // is 6645122; should be 101
...
}
Output:
response raw data: [101, 0, 0, 0, ...]
instance: InstanceMirror on Instance of '_Uint8ArrayView'
The IntelliJ debugger shows:
data = {List[id=1]} size = 101
> im = {_LocalInstanceMirror[id=2]} InstanceMirror on Instance of '_Uint8ArrayView'
_reflectee = {List[id=1]}
_type = null
hasReflectee = true
Dart supports the general ByteBuffer type which just represents a list of bytes as you can see here:
https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:typed_data.ByteBuffer
As the ByteBuffer class is abstract, you create lists from either receiving a ByteBuffer object or by instantiating a new list. The list usually is fixed length and working with it is hard. That's why you can create views from a ByteBuffer. A view represents a subset of the ByteBuffers bytes, given by an offset and a length which could also be the whole buffer.
Let's look at a small example:
import 'dart:typed_data';
void main() {
Uint8List data8 = new Uint8List.fromList([1,2,3,4,5,6,256]);
Uint16List data16 = new Uint16List.fromList([1,2,3,4,5,6,256]);
print(data8);
print(data16);
print(data8.buffer.lengthInBytes);
print(data16.buffer.lengthInBytes);
print(data16.buffer.asUint8List());
print(data16.buffer.asUint16List());
}
which gives you:
[1, 2, 3, 4, 5, 6, 0] // List
[1, 2, 3, 4, 5, 6, 256] // List
7
14
[1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 0, 1] // View
[1, 2, 3, 4, 5, 6, 256] // View
This means: ByteBuffer is some abstract class which gives you the interface and basic functionality and you can get views from a buffer to access the data as you need it.
The buffer accessed by 'data.buffer' is an internal buffer backing the Uint8List view referenced by 'data'. The transmitted payload -- what I want to wrap with the ByteData view -- is offset by some number of bytes into this buffer. The 'offset' of the payload can be determined through the 'offsetInBytes' property of the 'data' object. The following changes to decode() make it possible to use the ByteData API to decode various fragments of the payload byte array:
int offset = data.offsetInBytes; // sets offset to the starting position of the payload
int msgLength = bd.getInt32(offset);
double somethingElse = bd.getFloat64(offset+4);
// etc.

BlackBerry Decryption - BadPaddingException

I have successfully encrypted data in BlackBerry in AES format. In order to verify my result, I am trying to implement decryption in BlackBerry using the following method:
private static byte[] decrypt( byte[] keyData, byte[] ciphertext )throws CryptoException, IOException
{
// First, create the AESKey again.
AESKey key = new AESKey( keyData );
// Now, create the decryptor engine.
AESDecryptorEngine engine = new AESDecryptorEngine( key );
// Since we cannot guarantee that the data will be of an equal block length
// we want to use a padding engine (PKCS5 in this case).
PKCS5UnformatterEngine uengine = new PKCS5UnformatterEngine( engine );
// Create the BlockDecryptor to hide the decryption details away.
ByteArrayInputStream input = new ByteArrayInputStream( ciphertext );
BlockDecryptor decryptor = new BlockDecryptor( uengine, input );
// Now, read in the data. Remember that the last 20 bytes represent
// the SHA1 hash of the decrypted data.
byte[] temp = new byte[ 100 ];
DataBuffer buffer = new DataBuffer();
for( ;; ) {
int bytesRead = decryptor.read( temp );
buffer.write( temp, 0, bytesRead );
if( bytesRead < 100 ) {
// We ran out of data.
break;
}
}
byte[] plaintextAndHash = buffer.getArray();
int plaintextLength = plaintextAndHash.length - SHA1Digest.DIGEST_LENGTH;
byte[] plaintext = new byte[ plaintextLength ];
byte[] hash = new byte[ SHA1Digest.DIGEST_LENGTH ];
System.arraycopy( plaintextAndHash, 0, plaintext, 0, plaintextLength );
System.arraycopy( plaintextAndHash, plaintextLength, hash, 0,
SHA1Digest.DIGEST_LENGTH );
// Now, hash the plaintext and compare against the hash
// that we found in the decrypted data.
SHA1Digest digest = new SHA1Digest();
digest.update( plaintext );
byte[] hash2 = digest.getDigest();
if( !Arrays.equals( hash, hash2 )) {
throw new RuntimeException();
}
return plaintext;
}
I get an exception thrown "BadPaddingException" at the following line
int bytesRead = decryptor.read( temp );
Can anybody please help.
I think the problem might be in this block:
for( ;; ) {
int bytesRead = decryptor.read( temp );
buffer.write( temp, 0, bytesRead );
if( bytesRead < 100 ) {
// We ran out of data.
break;
}
}
When read returns -1, you are also writing it to the buffer. And the exit condition is also wrong. Compare that to the block in CryptoDemo sample project:
for( ;; ) {
int bytesRead = decryptor.read( temp );
if( bytesRead <= 0 )
{
// We have run out of information to read, bail out of loop
break;
}
db.write(temp, 0, bytesRead);
}
Also there are a few points you should be careful about, even if they are not causing the error:
AESDecryptorEngine engine = new AESDecryptorEngine( key );
If you read the docs for this constructor, it says:
"Creates an instance of the AESEncryptorEngine class given the AES key
with a default block length of 16 bytes."
But in the previous line, when you create the key, you are doing this:
AESKey key = new AESKey( keyData );
Which according to the docs, it "Creates the longest key possible from existing data.", BUT only "the first 128 bits of the array are used". So it does not matter what length your keyData has, you will always be using a 128 bit key length, which is the shortest of the 3 available sizes (128, 192, 256).
Instead, you could explicitly select the algorithm block key length. For instance, to use AES-256:
AESKey key = new AESKey(keyData, 0, 256); //key length in BITS
AESDecryptorEngine engine = new AESDecryptorEngine(key, 32); //key lenth IN BYTES
Finally, even if you get this working, you should be aware that directly deriving the key from the password (which might be of an arbitrary size) is not secure. You could use PKCS5KDF2PseudoRandomSource to derive an stronger key from the key material (password), instead of just using PKCS5 for padding.
Your encrypted data should be correctly padded to the block size (16 bytes).
Try to decrypt the data without padding, and see if tail bytes correspond to PKCS#5 padding (for instance, if it was needed 5 bytes of padding, it should be appended with 0x05 0x05 0x05 0x05 0x05 bytes).
The problem is that any data with the correct block size will decrypt. The issue with that is that it will likely decrypt to random looking garbage. Random looking garbage is not often compatible with the PKCS#7 padding scheme, hence the exception.
I say problem because this exception may be thrown if the key data is invalid, if the wrong padding or block mode was used or simply if the input data was garbled during the process. The best way to debug this is to make 100% sure that the algorithms match, and that the binary input parameters (including default ones by the API) match precisely on both sides.

Resources