Converting a C implementation of OpenSSL to Ruby code - c

In C I can do the following:
bignum = BN_new();
BN_bin2bn(my_message, 32, bignum);
group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
ecp = EC_POINT_new(group);
check = EC_POINT_set_compressed_coordinates_GFp(group, ecp, bignum, 0, NULL);
key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
check = EC_KEY_set_public_key(key, ecp);
check = EVP_PKEY_set1_EC_KEY(public_key, key);
In Ruby, I thought this would do the same thing, but I get an error*
bignum = OpenSSL::BN.new(my_message, 2)
group = OpenSSL::PKey::EC::Group.new('prime256v1')
group.point_conversion_form = :compressed
public_key = OpenSSL::PKey::EC::Point.new(group, bignum)
In both instances I can log bignum and see that it is the same, and I'm pretty positive prime256v1 is the correct group.
In both cases C and Ruby are using the same version of OpenSSL (OpenSSL 1.0.2p 14 Aug 2018)
Any advice on what I'm doing wrong here would be massively appreciated.
*The error message I get is invalid encoding (OpenSSL::PKey::EC::Point::Error)

The EC_POINT_set_compressed_coordinates_GFp function in C expects you to pass in the x-coordinate of the point and separately a value to specify which of the two possible points it could be (you are passing in a literal 0, in reality you should determine the actual value).
In Ruby, the Point initializer is expecting the point encoded as a string that includes information about both coordinates (I don’t know if this format has a name, but it’s pretty common and is documented by the SECG). In the case of compressed coordinates this string is basically the same 32 bytes as in the C code, but with an extra byte at the start, either 0x02 or 0x03, which correspond to passing 0 or 1 as the y-bit to EC_POINT_set_compressed_coordinates_GFp.
If the string doesn’t start with 0x02 or 0x03 (or 0x04 for uncompressed points) or is the wrong length, then you will get the invalid encoding error.
It doesn’t look like the Ruby OpenSSL bindings provide a way to specify a point using separate x and y coordinates. The simplest way would be to add the 0x02 or 0x03 prefix to the string before passing it to Point.new.
If you already have this string you can use it in C to create a point using EC_POINT_oct2point. Ruby itself calls EC_POINT_oct2point if you pass a string to Point.new.

Related

Kotlin. Get string part out of array of bytes

From a bluetooth device I get data in an array of bytes. 20 bytes are reserved for a string the other bytes contain data like short and int values.
The bytes for the string are converted to a string using Charset.UTF_8 (or US_ASCII). The problem is I can not get ride of the part that contains ordinary zero's like in other languages as c, c# and c++. Tried droplast after determining the first zero character. Nothing works. What am I missing.
The piece of code is this:
val bytes = job.characteristic.value
var index = 0;
var tempBytes = ByteArray(30)
while(index < 20) {
if (bytes[index] != 0.toByte())
tempBytes[index] = bytes[index]
else
break
++index
}
val newString = tempBytes.toString(Charsets.ISO_8859_1).dropLast(20 - index)
Log.i("BleDeviceVM", "Received for newString: " + newString)
Outcome in Android Studio is like this:
I/BleDeviceVM:
Received for newString: LEDServer��������������������
instead of:
LEDServer
*Thanks Broot.
Coming from c, c#, some c++ and some Java Kotlin is a bit confusing at first.This piece of code works fine I think:
var position = job.characteristic.value.indexOf(0)
if ((position > 20) || (-1 == position))
position = 20
_deviceID.value = String(job.characteristic.value, 0, position)
You have a bug in dropLast(). Your tempBytes is of size 30, but in dropLast you subtract index from 20, not from 30. This is why it is usually better to use constants or reference the collection size directly:
tempBytes.toString(Charsets.ISO_8859_1).dropLast(tempBytes.size - index)
Also, there is no need to use dropLast() if we need first n items, because take() does exactly this:
tempBytes.toString(Charsets.ISO_8859_1).take(index)
But honestly, your code is pretty overcomplicated. You can achieve a similar effect by replacing your whole code with simply:
val newString = String(bytes, 0, bytes.indexOf(0))
There are some differences comparing to your code, e.g. it searches past index 20 and it requires a null-byte somewhere. Depending on your specific case it may need to be adjusted.

Kotlin Int to Byte Conversion

What is the Kotlin 1.5 command to convert a 16 bit integer to a Byte of length 2? Secondary problem is that outputstream needs a string at the end so it can convert with toByteArray()
# Original Python Code
...
i = int((2**16-1)*ratio) # 16 bit int
i.to_bytes(2, byteorder='big')
output = (i).to_bytes(2, byteorder='big')
# Kotlin Code so far
var i = ((2.0.pow(16) - 1) * ratio).toInt() // Convert to 16 bit Integer
print("16 bit Int: " + i)
output = .....
....
...
val outputStream: OutputStream = socket.getOutputStream()
outputStream.write(output.toByteArray()) // write requires ByteArray for some reason
It is simple math, so it is probably the best to calculate manually and define as an extension function:
fun Int.to2ByteArray() : ByteArray = byteArrayOf(toByte(), shr(8).toByte())
Then you can use it:
output = i.to2ByteArray()
outputStream.write(output)
Note, this function writes the integer in little-endian. If you need big-endian the just reverse the order of items in the array. You can also add some min/max checks if you need them.
Also, if you only need 16-bit values then you can consider using Short or UShort instead of Int. It doesn't change much regarding the memory usage, but it could be a cleaner approach - we could name our extension just toByArray() and we would not need min/max checks.

Converting From a list of bits to a byte array

I am really struggling here as a new programming with a process using the snap7 library connected to a siemens PLC using Python3 on a raspberry PI. Basically I am reading in data as a byte array then modifying it and sending it back to the PLC. I am able to read it in and convert it to a list and modify the data.
So my data is a list that looks like [0,0,0,0,0,0,1,0]. It will always be exactly 1 byte (8 bits). So I can modify these bits. However I am struggling with getting them back into a byte array. I need to convert from that list into a byte array response that should look like bytearray(b'\x02')
Couple examples of what I am expecting
Input [0,0,0,0,0,0,0,1]
Output bytearray(b'\x01')
Input [0,0,0,0,0,0,1,0]
Output bytearray(b'\x02')
Input[0,0,0,0,0,0,1,1]
Output bytearray(b'\x03')
It is a bit odd that it is a byte array for only 1 byte but that is how the library works for writing to the datablock in the PLC.
Please let me know if there is any additional data I can share
Kevin
First convert the list to a decimal, this can be done in one line using.
sum(val*(2**idx) for idx, val in enumerate(reversed(binary)))
but to make the code a little more readable
binary_list = [0,0,0,0,0,0,1,0]
number = 0
for b in binary_list:
number = (2 * number) + b
Then simply use bytearray and add the number as an input
output = bytearray([number])
Changing this into a function
def create_bytearray(binary_list):
number = 0
for b in binary_list:
number = (2 * number) + b
return bytearray([number])
Now you just have to call
output = create_bytearray([0,0,0,0,0,0,1,0])
print(output)
And you will get
bytearray(b'\x02')

Inserting integer array with postgresql in C (libpq)

I'm trying to post an integer array into my postgresql database. I'm aware that I could format everything as a string and then send that string as one SQL command. However, I believe the PQexecParams function should also bring some help. However, I'm kind of lost as how to use it.
//we need to convert the number into network byte order
int val1 = 131;
int val2 = 2342;
int val3[5] = { 0, 7, 15, 31, 63 };
//set the values to use
const char *values[3] = { (char *) &val1, (char *) &val2, (char *) val3 };
//calculate the lengths of each of the values
int lengths[3] = { sizeof(val1), sizeof(val2), sizeof(val3) * 5 };
//state which parameters are binary
int binary[3] = { 1, 1, 1 };
PGresult *res = PQexecParams(conn, "INSERT INTO family VALUES($1::int4, $2::int4, $3::INTEGER[])", 3, //number of parameters
NULL, //ignore the Oid field
values, //values to substitute $1 and $2
lengths, //the lengths, in bytes, of each of the parameter values
binary, //whether the values are binary or not
0); //we want the result in text format
Yes this is copied from some tutorial.
However this returns :
ERROR: invalid array flags
Using a conventional method does work:
PQexec(conn, "INSERT INTO family VALUES (2432, 31, '{0,1,2,3,4,5}')");
Inserts data just fine, and I can read it out fine as well.
Any help would be greatly appreciated! :)
libpq's PQexecParams can accept values in text or binary form.
For text values, you must sprintf the integer into a buffer that you put in your char** values array. This is usually how it's done. You can use text format with query parameters, there is no particular reason to fall back to interpolating the parameters into the SQL string yourself.
If you want to use binary mode transfers, you must instead ensure the integer is the correct size for the target field, is in network byte order, and that you have specified the type OID. Use htonl (for uint32_t) or htons (for uint16_t) for that. It's fine to cast away signedness since you're just re-ordering the bytes.
So:
You cannot ignore the OID field if you're planning to use binary transfer
Use htonl, don't brew your own byte-order conversion
Your values array construction is wrong. You're putting char**s into an array of char* and casting away the wrong type. You want &val1[0] or (equivalent in most/all real-world C implementations, but not technically the same per the spec) just val1, instead of (char*)&val1
You cannot assume that the on-wire format of integer[] is the same as C's int32_t[]. You must pass the type OID INT4ARRAYOID (see include/catalog/pg_type.h or select oid from pg_type where typname = '_int4' - the internal type name of an array is _ in front of its base type) and must construct a PostgreSQL array value compatible with the typreceive function in pg_type for that type (which is array_recv) if you intend to send in binary mode. In particular, binary-format arrays have a header. You cannot just leave out the header.
In other words, the code is broken in multiple exciting ways and cannot possibly work as written.
Really, there is rarely any benefit in sending integers in binary mode. Sending in text-mode is often actually faster because it's often more compact on the wire (small values). If you're going to use binary mode, you will need to understand how C represents integers, how network vs host byte order works, etc.
Especially when working with arrays, text format is easier.
libpq could make this a lot easier than it presently does by offering good array construct / deconstruct functions for both text and binary arrays. Patches are, as always, welcome. Right now, 3rd party libraries like libpqtypes largely fill this role.

Need suggestion on Code conversion to Matlab_extension 2

This is an extension of the previously asked question: link. In a short, I am trying to convert a C program into Matlab and looking for your suggestion to improve the code as the code is not giving the correct output. Did I convert xor the best way possible?
C Code:
void rc4(char *key, char *data){
://Other parts of the program
:
:
i = j = 0;
int k;
for (k=0;k<strlen(data);k++){
:
:
has[k] = data[k]^S[(S[i]+S[j]) %256];
}
int main()
{
char key[] = "Key";
char sdata[] = "Data";
rc4(key,sdata);
}
Matlab code:
function has = rc4(key, data)
://Other parts of the program
:
:
i=0; j=0;
for k=0:length(data)-1
:
:
out(k+1) = S(mod(S(i+1)+S(j+1), 256)+1);
v(k+1)=double(data(k+1))-48;
C = bitxor(v,out);
data_show =dec2hex(C);
has = data_show;
end
It looks like you're doing bitwise XOR on 64-bit doubles. [Edit: or not, seems I forgot bitxor() will do an implicit conversion to integer - still, an implicit conversion may not always do what you expect, so my point remains, plus it's far more efficient to store 8-bit integer data in the appropriate type rather than double]
To replicate the C code, if key, data, out and S are not already the correct type you can either convert them explicitly - with e.g. key = int8(key) - or if they're being read from a file even better to use the precision argument to fread() to create them as the correct type in the first place. If this is in fact already happening in the not-shown code then you simply need to remove the conversion to double and let v be int8 as well.
Second, k is being used incorrectly - Matlab arrays are 1-indexed so either k needs to loop over 1:length(data) or (if the zero-based value of k is used as i and j are) then you need to index data by k+1.
(side note: who is x and where did he come from?)
Third, you appear to be constructing v as an array the same size of data - if this is correct then you should take the bitxor() and following lines outside the loop. Since they work on entire arrays you're needlessly repeating this every iteration instead of doing it just once at the end when the arrays are full.
As a general aside, since converting C code to Matlab code can sometimes be tricky (and converting C code to efficient Matlab code very much more so), if it's purely a case of wanting to use some existing non-trivial C code from within Matlab then it's often far easier to just wrap it in a MEX function. Of course if it's more of a programming exercise or way to explore the algorithm, then the pain of converting it, trying to vectorise it well, etc. is worthwhile and, dare I say it, (eventually) fun.

Resources