I'm using flutter_blue to communicate with a bluetooth device. I need to pass a double value to the bluetooth device using the flutter_blue write() method.
The value must be passed to the method as a list of integers which is supposed to represent a list of bytes as far as i understand it.
The flutter_blue write method:
Future<Null> write(
List<int> value,
{bool withoutResponse = false}
)
Is there a way to convert a double value to a list of integers that represents the double value as a list of bytes in order to pass it to flutter_blues write method?
For example:
double value = 10.52;
List<Int> convertedValue = someConversionMethod(value);
await bluetoothCharacteristic.write(convertedValue);
With Bluetooth it is normal to pass information as a list of bytes(Uint8List). The solution for float value is to have an expected exponent. There is more detail in the GATT Specification Supplement 4 especially in section 2 "Values and represented values"
If the number is large enough it will need to be converted to bytes in little endian format. As an example:
import 'dart:typed_data';
import 'dart:math';
void main() {
double value = 10.52;
var rawValue = value * pow(10, 2); // multiply value to remove decimal places
print('Raw value to send: $rawValue'); // Raw value to send 1052
var sendValue = ByteData(2);
sendValue.setUint16(0, rawValue.toInt(), Endian.little);
print('As Uint8List of values: ${sendValue.buffer.asUint8List()}');
// As Uint8List of values: [28, 4]
}
The dart:typed_data library has some useful methods to convert data to bytes. This method worked for me.
import 'dart:typed_data';
List<int> doubleToListInt(double value) {
ByteData bytes = ByteData(8);
bytes.setFloat64(0, value);
List<int> response =
bytes.buffer.asInt8List().toList();
return response;
}
print(doubleToListInt(10.52)); // Returns [64, 37, 10, 61, 112, -93, -41, 10]
Related
I want to encrypt the value with public key, I used pointycastle package and RSA and PKCS1 v1.5 padding, but this didn't work.
publicKey: 7/ZVKLxKXsQnlVUozywoumbFGbSz8kbH178dT165ODd/a/dUMAsdvs90iCLZo4KVoxZbQpD9d5K/Qgs1wjjylQ==
plainText:
a57b4b30-6b96-11ec-a8cf-c308568a983a
String encrypt(String plaintext, String publicKey) {
var modulusBytes = base64.decode(publicKey);
var modulus = BigInt.parse(hex.encode(modulusBytes), radix: 16);
var exponent = BigInt.parse(hex.encode(base64.decode('AQAB')), radix: 16);
var engine = RSAEngine()
..init(
true,
PublicKeyParameter<RSAPublicKey>(RSAPublicKey(modulus, exponent)),
);
//PKCS1.5 padding
var k = modulusBytes.length;
var plainBytes = utf8.encode(plaintext);
var paddingLength = k - 3 - plainBytes.length;
var eb = Uint8List(paddingLength + 3 + plainBytes.length);
var r = Random.secure();
eb.setRange(paddingLength + 3, eb.length, plainBytes);
eb[0] = 0;
eb[1] = 2;
eb[paddingLength + 2] = 0;
for (int i = 2; i < paddingLength + 2; i++) {
eb[i] = r.nextInt(254) + 1;
}
print(plainBytes.length);
print(eb);
return base64.encode(
engine.process(eb),
);
}
A couple of comments first...
Let's assume that the "public key" you provide is the modulus of an RSA key. We have to assume that the exponent is 65537. You'd normally want to get the public key in a PEM or similar. If that is the modulus, it's painfully short at just 512 bytes.
There only version of PKCS1 that's less than 2.x is 1.5. In particular, pointy castle's implementation in PKCS1Encoding is an implementation of 1.5.
You can only encrypt bytes. So, how are we meant to turn your "plaintext" into bytes. It could be a string that we could just encode in utf8. But it looks like a UUID. Maybe you are meant to interpret it as its normal representation as a 128 bit number, in bytes.
Finally, the output of the encryption will be bytes. How are you meant to send those to the server? Does it want them converted to a string first? If so, how? In base64? In hex?
The following code assumes: yes, that's a 512 bit modulus; the plaintext is not a UUID that can be interpreted, but is just a string that should be converted to ASCII bytes; the output is just an array of bytes.
import 'dart:convert';
import 'dart:typed_data';
import 'package:convert/convert.dart';
import 'package:pointycastle/export.dart';
void main() {
final publicKey =
'7/ZVKLxKXsQnlVUozywoumbFGbSz8kbH178dT165ODd/a/dUMAsdvs90iCLZo4KVoxZbQpD9d5K/Qgs1wjjylQ==';
final plaintext = 'a57b4b30-6b96-11ec-a8cf-c308568a983a';
var modulusBytes = base64.decode(publicKey);
var modulus = BigInt.parse(hex.encode(modulusBytes), radix: 16);
var exponent = BigInt.from(65537);
var engine = PKCS1Encoding(RSAEngine())
..init(
true,
PublicKeyParameter<RSAPublicKey>(RSAPublicKey(modulus, exponent)),
);
print(engine.process(utf8.encode(plaintext) as Uint8List));
}
var i=23FF;
how to convert this
convert i value in hex value like 0x23FF
ByteData mssg = ByteData(12);
mssg.setUint16(5, 0x23FF);
How I set hex value in ByteData
Thankyou
final hexString = myInteger.toRadixString(16); // 7e4
Convert it into String and count the number of places.
final paddedString = hexString.padLeft(count, '0x'); // 0x7e4
Decimal to Hex
String hex = 2020.toRadixString(16).padLeft(4, '0');
print(hex); // 07e4
Decimal to Binary (ByteData)
String binary = 2020.toRadixString(2);
print(binary); // 11111100100
Hex to Binary (ByteData)
String binary = hex.toRadixString(2);
print(binary); // 11111100100
What I wanna do is to input a string like ["01001000 01100101 01111001"] and convert it to ["Hey"] or the opposite too, input ["Hey"] and convert it to ["01001000 01100101 01111001"]
String encode(String value) {
// Map each code unit from the given value to a base-2 representation of this
// code unit, adding zeroes to the left until the string has length 8, and join
// each code unit representation to a single string using spaces
return value.codeUnits.map((v) => v.toRadixString(2).padLeft(8, '0')).join(" ");
}
String decode(String value) {
// Split the given value on spaces, parse each base-2 representation string to
// an integer and return a new string from the corresponding code units
return String.fromCharCodes(value.split(" ").map((v) => int.parse(v, radix: 2)));
}
void main() {
print(encode("Hey")); // Output: 01001000 01100101 01111001
print(decode("01001000 01100101 01111001")); // Output: Hey
}
I'm passing password into sha256. I successfully create sha256 and can also print it. The problem begins when I'm trying to convert digest.bytes into a string and append it.
import 'package:crypto/crypto.dart';
var url = "http://example_api.php?";
url += '&hash=';
// hash the password
var bytes = utf8.encode(password);
var digest = sha256.convert(bytes);
print("Digest as hex string: $digest");
url += String.fromCharCodes(digest.bytes);
This is printed: Digest as hex string: 03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4
This is appended to url: ¬gBóá\vá¥âUðg6#ȳ´Eùx×ÈFô
What am I doing wrong? I also tried utf8.decode method but using it gives me an error.
When you print digest, the print method will call digest.toString(), which is implemented to return a string of the digest bytes using a hexadecimal representation. If you want the same thing you have several options:
Call digest.toString() explicitly (or implicitly)
final digestHex = digest.toString(); // explicitly
final digestHex = '$digest'; // implicitly
Map the byte array to its hexadecimal equivalent
final digestHex = digest.bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join();
Use the convert package (this is what the crypto package does)
import 'package:convert/convert.dart';
...
final digestHex = hex.encode(digest.bytes);
The reason you are getting an error using utf8.decode is that your digest isn't an encoded UTF-8 string but a list of bytes that for all intents and purposes are completely random. You are trying to directly convert the bytes into a string, and doing so is easier if you can assume that they already represent a valid string. With the byte output from a hashing algorithm, though, you cannot safely make such an assumption.
However, if for some reason you still want to use this option, use the second optional parameter for utf8.decode to force it to try and decode the bytes anyway:
final digestString = utf8.decode(bytes, allowMalformed: true);
For reference, a byte list of [1, 255, 47, 143, 6, 80, 33, 202] results in "�/�P!�" where "�" represents an invalid/control character. You do not want to use this option, especially where the string will become part of a URL (as it's virtually guaranteed that the resulting string will not be web-safe).
For the hexadecimal representation of a Digest object, please explicitly call Digest.toString() (though in formatted strings, i.e. "url${digest}", this is done for you implicitly).
I'm frankly not familiar with String.fromCharCode, but I think it's looking for UTF-16 and not UTF-8 bits. I wrote a terminal example to show this, and how the outputs differ.
import 'dart:core';
import 'dart:convert';
import 'package:crypto/crypto.dart';
void main() {
const String password = "mypassword";
// hash the password
var bytes = utf8.encode(password);
var digest = sha256.convert(bytes);
// different formats
var bytesDigest = digest.bytes;
var hexDigest = digest.toString();
String url = "http://example_api.php?hash=";
print(url + hexDigest);
print(url + String.fromCharCodes(bytesDigest));
}
Output:
> dart test.dart
http://example_api.php?hash=89e01536ac207279409d4de1e5253e01f4a1769e696db0d6062ca9b8f56767c8
http://example_api.php?hash=à6¬ ry#Ö,©¸õggÈ
I am trying to convert Data to UnsafePointer. I found an answer here where I can use withUnsafeBytes to get the bytes.
Then I did a small test my self to see I could just print out the bytes value of the string "abc"
let testData: Data = "abc".data(using: String.Encoding.utf8)!
testData.withUnsafeBytes(
{(bytes: UnsafePointer<UInt8>) -> Void in
NSLog("\(bytes.pointee)")
})
But the output is just the value of one character, which is "a".
2018-07-11 14:40:32.910268+0800 SwiftTest[44249:651107] 97
How could I get the byte value of all three characters then?
The "pointer" points to the address of the first byte in the sequence. If you want to want a pointer to the other bytes, you have to use pointer arithmetic, that is, move the pointer to the next address:
testData.withUnsafeBytes{ (bytes: UnsafePointer<UInt8>) -> Void in
NSLog("\(bytes.pointee)")
NSLog("\(bytes.successor().pointee)")
NSLog("\(bytes.advanced(by: 2).pointee)")
}
or
testData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
NSLog("\(bytes[0])")
NSLog("\(bytes[1])")
NSLog("\(bytes[2])")
}
However, you must be aware of the byte size of testData and don't overflow it.
You are getting '97' because 'bytes' is pointing to the staring address of the 'testdata'.
you can get byte value of all three OR n number of characters like in the following code :
let testData: Data = "abc".data(using: String.Encoding.utf8)!
print(testData.count)
testData.withUnsafeBytes(
{(bytes: UnsafePointer<UInt8>) -> Void in
for idx in 0..<testData.count {
NSLog("\(bytes[idx])")
}
})