C# RSACryptoServiceProvider.Encrypt has an equivalent to PHP function - c#

I have assigned to convert some C# code to PHP. I really don't have knowledge in C# or on any Microsoft Programming languages. I need to connect to a web service with RSA encryption, they gave the public key and a sample code made in C# (that I need to convert). Below is the C# code:
//SAMPLE data to encrypt
var data = "dfsdfpamf12031ad";
var flStr = "<BitStrength>1024</BitStrength><RSAKeyValue><Modulus>** some keys **</Modulus><Exponent>**exponent value **</Exponent></RSAKeyValue>";
var bitStr = flStr.Substring(0, flStr.IndexOf("</BitStrength>", StringComparison.InvariantCultureIgnoreCase) + 14);
flStr = flStr.Replace(bitStr, "");
var bitStrength = Convert.ToInt32(bitStr.Replace("<BitStrength>", "").Replace("</BitStrength>", ""));
using (var rsaCrypto = new rsaCrypto(bitStrength))
{
rsaCrypto.FromXmlString(flStr);
var keySize = bitStrength / 8;
var bytes = Encoding.UTF32.GetBytes(data);
var maxLength = keySize - 42;
var dataLength = bytes.Length;
var iterations = dataLength / maxLength;
var returnStr = new returnStr();
for (var i = 0; i <= iterations; i++)
{
var tempBytes = new byte[(dataLength - maxLength * i > maxLength) ? maxLength : dataLength - maxLength * i]; // **i=0 ~ 86; i=1 ~ 42;**
Buffer.BlockCopy(bytes, maxLength * i, tempBytes, 0, tempBytes.Length);
var encryptedBytes = rsaCrypto.Encrypt(tempBytes, true);
returnStr.Append(Convert.ToBase64String(encryptedBytes));
}
return returnStr.ToString();
}
I don't think if there is a RSA byte encryption in PHP. I believe PHP don't have a byte data type. I tried to use openssl_public_encrypt function and phpseclib library but I think 86 and 42 when encrypted it considers it an integer data type not byte.
I'll appreciate any inputs regarding on this problem. Thanks in advance! :)

Related

How do I sign a TransactionHex with SeedHex using secp256k1 in C# with Bouncy Castle?

I have this nodejs snippet which I want to implement in C#.
The SignTransaction function takes in a seedHex string (length: 64) and a TransactionHex string, a signature is created using secp256k1 algorithm and appended to the end of the TransactionHex.
const sha256 = require('sha256');
const EC = require('elliptic').ec;
const ec = new EC("secp256k1");
// Serialize a number into an 8-byte array. This is a copy/paste primitive, not worth
// getting into the details.
function uvarint64ToBuf (uint) {
const result = [];
while (uint >= 0x80) {
result.push((uint & 0xFF) | 0x80);
uint >>>= 7;
}
result.push(uint | 0);
return new Buffer(result);
}
// Sign transaction with seed
function signTransaction (seed, txnHex) {
const privateKey = ec.keyFromPrivate(seed);
const transactionBytes = new Buffer(txnHex, 'hex');
const transactionHash = new Buffer(sha256.x2(transactionBytes), 'hex');
const signature = privateKey.sign(transactionHash);
const signatureBytes = new Buffer(signature.toDER());
const signatureLength = uvarint64ToBuf(signatureBytes.length);
const signedTransactionBytes = Buffer.concat([
transactionBytes.slice(0, -1),
signatureLength,
signatureBytes
])
return signedTransactionBytes.toString('hex');
}
example transaction hex
01efa5060f5fdae5ed9d90e5f076b2c328a64e347d0c87e8e3317daec5a44fe7c8000102bd53e48625f49e60ff6b7a934e3871b54cc2a93a8737352e8320549e42e2322bab0405270000167b22426f6479223a2248656c6c6f20576f726c64227de807d461f4df9efad8a0f3f716002102bd53e48625f49e60ff6b7a934e3871b54cc2a93a8737352e8320549e42e2322b0000
example signed transaction hex returned from the javascript function
01efa5060f5fdae5ed9d90e5f076b2c328a64e347d0c87e8e3317daec5a44fe7c8000102bd53e48625f49e60ff6b7a934e3871b54cc2a93a8737352e8320549e42e2322bab0405270000167b22426f6479223a2248656c6c6f20576f726c64227de807d461f4df9efad8a0f3f716002102bd53e48625f49e60ff6b7a934e3871b54cc2a93a8737352e8320549e42e2322b00473045022100c36e2b80f2160304cf640b1296244e7a3873aacf2831098bca3727ad06f4c270022007d3697ceef266a05ad70219d92fbd570f6ec7a5731aaf02718213067d42d1cf
If you notice the signed hex is TransactionHex + 47 (length of signature) + 473045022100c36e2b80f2160304cf640b1296244e7a3873aacf2831098bca3727ad06f4c270022007d3697ceef266a05ad70219d92fbd570f6ec7a5731aaf02718213067d42d1cf (actual signature)
I am trying to use C# Bouncy Castle library in Unity3d to generate the signature part but no success.
This is the C# code (source)
public string GetSignature(string privateKey, string message)
{
var curve = SecNamedCurves.GetByName("secp256k1");
var domain = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H);
var keyParameters = new ECPrivateKeyParameters(new BigInteger(privateKey, 16), domain);
var signer = new ECDsaSigner(new HMacDsaKCalculator(new Sha256Digest()));
signer.Init(true, keyParameters);
var signature = signer.GenerateSignature(Encoding.UTF8.GetBytes(message));
var r = signature[0];
var s = signature[1];
var otherS = curve.Curve.Order.Subtract(s);
if (s.CompareTo(otherS) == 1)
{
s = otherS;
}
var derSignature = new DerSequence
(
new DerInteger(new BigInteger(1, r.ToByteArray())),
new DerInteger(new BigInteger(1, s.ToByteArray()))
)
.GetDerEncoded();
return Convert(derSignature);
}
public string Convert(byte[] input)
{
return string.Concat(input.Select(x => x.ToString("x2")));
}
public byte[] Convert(string input)
{
if (input.StartsWith("0x")) input = input.Remove(0, 2);
return Enumerable.Range(0, input.Length / 2).Select(x => System.Convert.ToByte(input.Substring(x * 2, 2), 16)).ToArray();
}
This does generate a signature but it is not identical to the one I mentioned above.
Signature generated from GetSignature
3044022018a06b1f2b8a1e2f5ea2a78b0d6d98ec483b9fa4345821cfef892be6c825ff4702207958160e533c801dff5e50600206e1cd938d6df74ebfa4b0347a95de67dda986
P.S. Here is the python equivalent of signing transactions for reference.
sha256.x2() in the NodeJS code hashes twice, while ECDsaSigner in the C# code does not hash at all. Therefore, in the C# code, GetSignature() must explicitly hash twice:
using Org.BouncyCastle.Crypto.Digests;
...
var messageBytes = Convert(message);
var hash = GetHash(GetHash(messageBytes));
var signature = signer.GenerateSignature(hash);
...
with
private static byte[] GetHash(byte[] data)
{
var digest = new Sha256Digest();
var hash = new byte[digest.GetDigestSize()];
digest.BlockUpdate(data, 0, data.Length);
digest.DoFinal(hash, 0);
return hash;
}
Since both codes use the deterministic ECDSA algorithm according to RFC6979, the hashes for the same input data are identical and can be compared.
The overall result is the concatenation of txnHex without the last byte, the hex encoded length of the signature and the signature in ASN.1/DER format; a possible implementation is:
var txnHex = "...";
var seed = "...";
string signature = GetSignature(seed, txnHex);
string signedTransactionBytes = txnHex.Substring(0, txnHex.Length - 2) + (signature.Length / 2).ToString("x") + signature;
Note that the uvarint64ToBuf() implementation is actually more complex, but can be simplified for the signature lengths used here.

AES encryption in NI LabVIEW

How do I implement AES encryption and decryption in LabVIEW and configure the following settings?
Padding = PaddingMode.PKCS7
Mode = CipherMode.CBC
Key Size = 128
Block Size = 128
I have tried few option over here Igor Titov, AES Crypto Toolkit by Alab Technologies
Tried to reach both parties to confirm if those toolkits support above configuration, but they don't respond on phone or email.
Any help is greatly appreciated.
I found this code from Igor Titov
Encrypt:https://github.com/IgorTitov/LabVIEW-Advanced-Encryption-Standard/blob/master/Encrypt%20with%20AES.vi
/**
* Encrypt a text using AES encryption in Counter mode of operation
*
* Unicode multi-byte character safe
*
* #param plaintext Source text to be encrypted
* #param password The password to use to generate a key
* #param nBits Number of bits to be used in the key (128, 192, or 256)
* #returns Encrypted text
*/
public function encrypt(plaintext : String, password : String, nBits : int) : String //Done in LV
{
var blockSize : int = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
if (!(nBits == BIT_KEY_128 || nBits == BIT_KEY_192 || nBits == BIT_KEY_256))
{
// standard allows 128/192/256 bit keys
throw new Error("Must be a key mode of either 128, 192, 256 bits");
}
plaintext = Utf8.encode(plaintext);
password = Utf8.encode(password);
// use AES itself to encrypt password to get cipher key (using plain password as source for key
// expansion) - gives us well encrypted key
var nBytes : int = nBits / 8; // no bytes in key
var pwBytes : Array = new Array(nBytes);
for (var i : int = 0;i < nBytes;i++)
{
pwBytes[i] = isNaN(password.charCodeAt(i)) ? 0 : password.charCodeAt(i);
}
var key : Array = cipher(pwBytes, keyExpansion(pwBytes)); // gives us 16-byte key
key = key.concat(key.slice(0, nBytes - 16)); // expand key to 16/24/32 bytes long
// initialise counter block (NIST SP800-38A §B.2): millisecond time-stamp for nonce in 1st 8 bytes,
// block counter in 2nd 8 bytes
var counterBlock : Array = new Array(blockSize);
var nonce : int = 123456789;////DEBUG!!!(new Date()).getTime(); // timestamp: milliseconds since 1-Jan-1970
var nonceSec : int = Math.floor(nonce / 1000);
var nonceMs : int = nonce % 1000;
// encode nonce with seconds in 1st 4 bytes, and (repeated) ms part filling 2nd 4 bytes
for (i = 0;i < 4;i++)
{
counterBlock[i] = (nonceSec >>> (i * 8)) & 0xff;
}
for (i = 0;i < 4;i++)
{
counterBlock[i + 4] = nonceMs & 0xff;
}
// and convert it to a string to go on the front of the ciphertext
var ctrTxt : String = '';
for (i = 0;i < 8;i++)
{
ctrTxt += String.fromCharCode(counterBlock[i]);
}
// generate key schedule - an expansion of the key into distinct Key Rounds for each round
var keySchedule : Array = keyExpansion(key);
var blockCount : int = Math.ceil(plaintext.length / blockSize);
var ciphertxt : Array = new Array(blockCount); // ciphertext as array of strings
for (var b : int = 0;b < blockCount;b++)
{
// set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
// done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB)
for (var c : int = 0;c < 4;c++)
{
counterBlock[15 - c] = (b >>> (c * 8)) & 0xff;
}
for (c = 0;c < 4;c++)
{
counterBlock[15 - c - 4] = (b / 0x100000000 >>> c * 8);
}
var cipherCntr : Array = cipher(counterBlock, keySchedule); // -- encrypt counter block --
// block size is reduced on final block
var blockLength : int = b < blockCount - 1 ? blockSize : (plaintext.length - 1) % blockSize + 1;
var cipherChar : Array = new Array(blockLength);
for (i = 0;i < blockLength;i++)
{
// -- xor plaintext with ciphered counter char-by-char --
cipherChar[i] = cipherCntr[i] ^ plaintext.charCodeAt(b * blockSize + i);
//trace("i=",i,"plaintext.charCodeAt(b * blockSize + i)",plaintext.charCodeAt(b * blockSize + i),"cipherChar[i]=",cipherChar[i]);
cipherChar[i] = String.fromCharCode(cipherChar[i]);
}
ciphertxt[b] = cipherChar.join('');
//trace(ciphertxt);
}
// Array.join is more efficient than repeated string concatenation in IE
var ciphertext : String = ctrTxt + ciphertxt.join('');
//trace("before 64 encode:",ciphertext);
ciphertext = Base64.encode(ciphertext); // encode in base64
//trace("after 64 encode:",ciphertext);
//alert((new Date()) - t);
return ciphertext;
}
Decrypt: https://github.com/IgorTitov/LabVIEW-Advanced-Encryption-Standard/blob/master/Decrypt%20with%20AES.vi
/**
* Decrypt a text encrypted by AES in counter mode of operation
*
* #param ciphertext Source text to be encrypted
* #param password The password to use to generate a key
* #param nBits Number of bits to be used in the key (128, 192, or 256)
* #returns Decrypted text
*/
public function decrypt(ciphertext : String, password : String, nBits : int) : String
{
var blockSize : int = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
if (!(nBits == BIT_KEY_128 || nBits == BIT_KEY_192 || nBits == BIT_KEY_256)) {
// standard allows 128/192/256 bit keys
throw new Error("Must be a key mode of either 128, 192, 256 bits");
}
ciphertext = Base64.decode(ciphertext.split("\n").join(""));
password = Utf8.encode(password);
//var t = new Date(); // timer
// use AES to encrypt password (mirroring encrypt routine)
var nBytes : int = nBits / 8; // no bytes in key
var pwBytes : Array = new Array(nBytes);
for (var i : int = 0;i < nBytes;i++)
{
pwBytes[i] = isNaN(password.charCodeAt(i)) ? 0 : password.charCodeAt(i);
}
var key : Array = cipher(pwBytes, keyExpansion(pwBytes));
key = key.concat(key.slice(0, nBytes - 16)); // expand key to 16/24/32 bytes long
// recover nonce from 1st 8 bytes of ciphertext
var counterBlock : Array = new Array(8);
var ctrTxt : String = ciphertext.slice(0, 8);
for (i = 0;i < 8;i++)
{
counterBlock[i] = ctrTxt.charCodeAt(i);
}
// generate key schedule
var keySchedule : Array = keyExpansion(key);
// separate ciphertext into blocks (skipping past initial 8 bytes)
var nBlocks : int = Math.ceil((ciphertext.length - 8) / blockSize);
var ct : Array = new Array(nBlocks);
for (b = 0;b < nBlocks;b++)
{
ct[b] = ciphertext.slice(8 + b * blockSize, 8 + b * blockSize + blockSize);
//trace("ct[b]=",ct[b],"blockSize=",blockSize,8 + b * blockSize, 8 + b * blockSize + blockSize);
}
//var temp:String=ct[1];
// for (var i:int=0;i<temp.length;i++)
// {
// trace("ct[1]Byte Array:",temp.charCodeAt(i));
// }
var ciphertextArr : Array = ct; // ciphertext is now array of block-length strings
// plaintext will get generated block-by-block into array of block-length strings
var plaintxt : Array = new Array(ciphertextArr.length);
for (var b : int = 0;b < nBlocks;b++)
{
// set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
for (var c : int = 0;c < 4;c++)
{
counterBlock[15 - c] = ((b) >>> c * 8) & 0xff;
}
for (c = 0;c < 4;c++)
{
counterBlock[15 - c - 4] = (((b + 1) / 0x100000000 - 1) >>> c * 8) & 0xff;
}
//trace(counterBlock);
var cipherCntr : Array = cipher(counterBlock, keySchedule); // encrypt counter block
//trace(cipherCntr);
var plaintxtByte : Array = new Array(String(ciphertextArr[b]).length);
for (i = 0;i < String(ciphertextArr[b]).length;i++)
{
// -- xor plaintxt with ciphered counter byte-by-byte --
plaintxtByte[i] = cipherCntr[i] ^ String(ciphertextArr[b]).charCodeAt(i);
//trace("i=",i,"plaintxtByte[i]=",plaintxtByte[i],"cipherCntr[i]=",cipherCntr[i],"String(ciphertextArr[b]).charCodeAt(i)=",String(ciphertextArr[b]).charCodeAt(i));
//trace(plaintxtByte[i]);
plaintxtByte[i] = String.fromCharCode(plaintxtByte[i]);
}
plaintxt[b] = plaintxtByte.join('');
}
// join array of blocks into single plaintext string
var plaintext : String = plaintxt.join('');
plaintext = Utf8.decode(plaintext); // decode from UTF8 back to Unicode multi-byte chars
return plaintext;
}
Not sure what programming language is this. If I can get help in converting this code to C# that will solve my blocker.
Here is the VI snippet.
I did something similar with blowfish but am not familiar with the AES implementation by Alab Tech.
Assuming the Alab Tech library function correctly, just pad your data as necessary before encrypting it.
KCS7 (described in RFC 5652). This pads data to the blocksize with the
number that is equal to the number of added bytes. If the original
data is an integer multiple of N bytes, then an extra block of bytes
with value N is added
That sounds relatively straightforward and a simple block diagram as below shows how it might work:

MD5 of an UTF16LE (without BOM and 0-Byte End) in Javascript (C# Example provided)

I am sitting a few days on the following problem: I need to get a MD5 Hash of a UTF16-LE encoded string in JavaScript. I have an Example how to do this in C# but do not know how to do this in JavaScript.
Example:
public string GetMD5Hash (string input) {
MD5 md5Hasher = MD5.Create();
byte[] data = md5Hasher.ComputeHash(Encoding.Unicode.GetBytes(input));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.Length; i++) {
sb.Append(data[i].ToString("x2"));
}
return sb.ToString();
}
Wanted:
var getMD5Hash(input){
....
}
var t = getMD5Hash("1234567z-äbc");
console.log(t) // --> 9e224a41eeefa284df7bb0f26c2913e2
I hope some one can help me :-/
Here you go
return challenge + "-" + require('crypto').createHash('md5').update(Buffer(challenge+'-'+password, 'UTF-16LE')).digest('hex')
let md5 = require('md5');
function getMD5_UTF16LE(str){
let bytes = [];
for (let i = 0; i < str.length; ++i) {
let code = str.charCodeAt(i);
bytes = bytes.concat([code & 0xff, code / 256 >>> 0]);
}
return md5(bytes);
}
needs library https://www.npmjs.com/package/md5

Trying to reproduce PHP's pack("H*") function in C#

this is my code in C# :
public static String MD5Encrypt(String str, Boolean raw_output=false)
{
// Use input string to calculate MD5 hash
String output;
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(str);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// Convert the byte array to hexadecimal string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("x2"));
}
output = sb.ToString();
if (raw_output)
{
output = pack(output);
}
return output;
}
public static String pack(String S)
{
string MultiByte = "";
for (int i = 0; i <= S.Length - 1; i += 2)
{
MultiByte += Convert.ToChar(HexToDec(S.Substring(i, 2)));
}
return MultiByte;
}
private static int HexToDec(String hex)
{
//Int32.Parse(hexString, System.Globalization.NumberStyles.HexNumber);
return Convert.ToInt32(hex, 16);
}
To reproduce what is done in php by this way :
md5($str, true);
OR
pack('H*', md5( $str ));
I tried many things but can't get the same on the two sides in some cases of word.
For example, Trying this test on the string "8tv7er5j"
PHP Side :
9c36ad446f83ca38619e12d9e1b3c39e <= md5("8tv7er5j");
œ6­DoƒÊ8ažÙá³Ãž <= md5("8tv7er5j", true) or pack("H*", md5("8tv7er5j"))
C# Side :
9c36ad446f83ca38619e12d9e1b3c39e <= MD5Encrypt("8tv7er5j")
6­DoÊ8aÙá³Ã <= MD5Encrypt("8tv7er5j", true) or pack( MD5Encrypt("8tv7er5j") )
Why ? Encoding problem ?
EDIT 1 :
I have the good result, but bad encoded with this this function for pack() :
if ((hex.Length % 2) == 1) hex += '0';
byte[] bytes = new byte[hex.Length / 2];
for (int i = 0; i < hex.Length; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
So, System.Text.Encoding.UTF8.GetString(bytes) give me :
�6�Do��8a���Þ
And System.Text.Encoding.ASCII.GetString(bytes)
?6?Do??8a??????
...
I encountered same scenario where I am in need of php's pack-unpack-md5 functions in C#. Most important was that I need to match out of all these 3 functions with php.
I created my own functions and then validated(verified) my output with functions at onlinephpfunctions.com. The output was same when I parsed with DefaultEncoding. FYI, I checked my application's encoding(Encoding.Default.ToString()) and it was System.Text.SBCSCodePageEncoding
Pack
private static string pack(string input)
{
//only for H32 & H*
return Encoding.Default.GetString(FromHex(input));
}
public static byte[] FromHex(string hex)
{
hex = hex.Replace("-", "");
byte[] raw = new byte[hex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
return raw;
}
MD5
private static string md5(string input)
{
byte[] asciiBytes = Encoding.Default.GetBytes(input);
byte[] hashedBytes = MD5CryptoServiceProvider.Create().ComputeHash(asciiBytes);
string hashedString = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
return hashedString;
}
Unpack
private static string unpack(string p1, string input)
{
StringBuilder output = new StringBuilder();
for (int i = 0; i < input.Length; i++)
{
string a = Convert.ToInt32(input[i]).ToString("X");
output.Append(a);
}
return output.ToString();
}
PS: User can enhance these functions with other formats
I guess that PHP defaults to Latin1 so the code should look like :
public static String PhpMd5Raw(string str)
{
var md5 = System.Security.Cryptography.MD5.Create();
var inputBytes = System.Text.Encoding.ASCII.GetBytes(str);
var hashBytes = md5.ComputeHash(inputBytes);
var latin1Encoding = System.Text.Encoding.GetEncoding("ISO-8859-1");
return latin1Encoding.GetString(hashBytes);
}
If you are going to feed the result as a key for HMAC-SHA1 hashing keep it as bytes[] and initialize the HMACSHA1 with the return value of this function: DO NOT convert it to a string and back to bytes, I have spent hours because of this mistake.
public static byte[] PackH(string hex)
{
if ((hex.Length % 2) == 1) hex += '0';
byte[] bytes = new byte[hex.Length / 2];
for (int i = 0; i < hex.Length; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
I know this is an old question. I am posting my answer for anyone who might reach this page searching for it.
The following code is the full conversion of the pearl function pack("H*") to c#.
public static String Pack(String input)
{
input = input.Replace("-", " ");
byte[] hashBytes = new byte[input.Length / 2];
for (int i = 0; i < hashBytes.Length; i++)
{
hashBytes[i] = Convert.ToByte(input.Substring(i * 2, 2), 16);
}
return Encoding.UTF7.GetString(hashBytes); // for perl/php
}
I'm sorry. I didn't go with the questions completely. But if php code is as below,
$testpack = pack("H*" , "you value");
and if can't read the $testpack values(due to some non support format), then first do base64_encode as below and echo it.
echo base64_encode($testpack);
Then use Risky Pathak answer. For complete this answer I'll post his answer with some small modification like base 64 encoding etc.
var hex = "you value";
hex = hex.Replace("-", "");
byte[] raw = new byte[hex.Length / 2];
for (int i = 0; i < raw.Length; i++)
{
raw[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
}
var res = Convert.ToBase64String(raw);
Console.WriteLine(res);
Now if you compare both of values, those should be similar.
And all credit should go to the Risky Pathak answer.
The same in c# can be reached with Hex.Decode() method.
And bin2hex() in php is Hex.Encode().

Generating 40 char fingerprint for DSA

Is there a existing method within .NET Framework (C#) to generate a 40 char (public?) fingerprint as shown below, when you have P, Q, G, Y and X?
Or would anybody know on how to achieve this?
Fingerprint: 81F68001 29D928AD BEE41B78 AA862106 CAEAC892
EDIT:
here is an example of what i'm trying to do:
string P = "00F35DBCD6D4C296D2FE9118B659D02608B76FAC94BB58B10283F20390E2B259BAC602466162E9EF3E6A1590702CAE49B681A75A878E266F1AFAE0FA89DA5CA44A1551B517A3F80A9D6C630F9E7D239B437F7402DF8055069735894CD9D4708F8777B5E4F3E6A8B2D4EEE50DB2C96BA16D3C81FEB923697D649A8B7771B10E5B3F";
string Q = "00B5AF039839043410E04C35BDDB30679969EBAC8B";
string G = "00F300A68E54DE33A09001E28EC09F2ABF5DAF208774F2514D878D5587D870C91C6DE42B4705078C6F4438765050039C2950B6DE85AFC0D12A7A5C521782CB760918DF68F385A7F177DF50AA6BA0284090454106E422FCAE5390ADC00B859A433430019E970BFA614374DE1FB40C600345EF19DC01A122E4676C614DC29D3DC2FE";
string Y = "00A5317849AF22BA6498F1EF973158C8BDA848BEB074CB141E629C927B18F29C8CE99815001BAAB2931F339B5C52A79BC3DCB0C5962C302707BA6FF1807EEB91D751BA723BB7512C20689AC5E67A1B656CDFD1BA2D4F6A44308509486AA8754B47784FC4C03E546897200388656BA5834A2CC0E18E58454FF60C1BA5411D6F50FD";
i'm missing the code for this intermediate piece. how do i convert P, Q, G, Y into the fingerprint. I tried different approaches, but i'm unsuccessful generating the fingerprint i see in the application that i'm trying to recreate.
/* convert public key (bigIntKey) into fingerprint */
var bigIntHash = new BigInteger(SHA1.Create().ComputeHash(key.ToByteArray()));
byte[] hash = bigIntHash.ToByteArray();
if (hash.Length != 20)
{
throw new IndexOutOfRangeException();
}
for (int i = 0; i < 5; i++)
{
int lf = BitConverter.ToInt32(hash, i * 4);
Debug.Write(lf.ToString("X") + " ");
}
EDIT2:
i tried this, but that is not working
// switch P, Q, G, Y and separately to make it work.
byte[] pArr = StringToByteArray(P);
pArr = Tools.Endian.ReverseBytes(pArr);
byte[] qArr = StringToByteArray(Q);
qArr = Tools.Endian.ReverseBytes(qArr);
byte[] gArr = StringToByteArray(G);
gArr = Tools.Endian.ReverseBytes(gArr);
byte[] yArr = StringToByteArray(Y);
yArr = Tools.Endian.ReverseBytes(yArr);
byte[] xArr = StringToByteArray(X);
xArr = Tools.Endian.ReverseBytes(xArr);
byte[] arr = Combine(pArr, qArr, gArr, yArr);
DSACryptoServiceProvider dsa = new DSACryptoServiceProvider();
DSAParameters par = new DSAParameters();
par.P = pArr;
par.Q = qArr;
par.G = gArr;
par.Y = yArr;
par.X = xArr;
dsa.ImportParameters(par);
var xml = dsa.ToXmlString(true);
It will fail on the ImportParameter.
Thank you
You need to follow the OTR spec, which says the components of the key use MPI encoding, which it specifies as the length (32 bit big-endian) followed by the integer (big-endian, no leading zeros)
void Main()
{
string P = "00F35DBCD6D4C296D2FE9118B659D02608B76FAC94BB58B10283F20390E2B259BAC602466162E9EF3E6A1590702CAE49B681A75A878E266F1AFAE0FA89DA5CA44A1551B517A3F80A9D6C630F9E7D239B437F7402DF8055069735894CD9D4708F8777B5E4F3E6A8B2D4EEE50DB2C96BA16D3C81FEB923697D649A8B7771B10E5B3F";
string Q = "00B5AF039839043410E04C35BDDB30679969EBAC8B";
string G = "00F300A68E54DE33A09001E28EC09F2ABF5DAF208774F2514D878D5587D870C91C6DE42B4705078C6F4438765050039C2950B6DE85AFC0D12A7A5C521782CB760918DF68F385A7F177DF50AA6BA0284090454106E422FCAE5390ADC00B859A433430019E970BFA614374DE1FB40C600345EF19DC01A122E4676C614DC29D3DC2FE";
string Y = "00A5317849AF22BA6498F1EF973158C8BDA848BEB074CB141E629C927B18F29C8CE99815001BAAB2931F339B5C52A79BC3DCB0C5962C302707BA6FF1807EEB91D751BA723BB7512C20689AC5E67A1B656CDFD1BA2D4F6A44308509486AA8754B47784FC4C03E546897200388656BA5834A2CC0E18E58454FF60C1BA5411D6F50FD";
var publicKey =
ToMPI(HexToBytes(P))
.Concat(ToMPI(HexToBytes(Q)))
.Concat(ToMPI(HexToBytes(G)))
.Concat(ToMPI(HexToBytes(Y)))
.ToArray();
var fingerprint=BitConverter.ToString(SHA1.Create().ComputeHash(publicKey)).Replace("-","");
fingerprint.Dump();
}
byte[] ToMPI(byte[] data)
{
//Truncate leading 0 bytes
data = data.SkipWhile(b=>b==0).ToArray();
//Length prefix - 32 bit big-endian integer
var lenBytes=new byte[4];
lenBytes[0]=(byte)(data.Length>>24);
lenBytes[1]=(byte)(data.Length>>16);
lenBytes[2]=(byte)(data.Length>>8);
lenBytes[3]=(byte)(data.Length>>0);
return lenBytes.Concat(data).ToArray();
}
// from http://stackoverflow.com/questions/311165/how-do-you-convert-byte-array-to-hexadecimal-string-and-vice-versa
public static byte[] HexToBytes(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
MSDN mentions what you need to do your job on this page.
Then, have a look at this answer from this SO page. The accepted answer gives the following code (and I quote):
var dsa = new DSACryptoServiceProvider();
var privateKey = dsa.ExportParameters(true); // private key
var publicKey = dsa.ExportParameters(false); // public key
I think you have everything you need to get you going.
CHEERS!
I've used this class to generate a OTR DSA key:
https://github.com/mohamedmansour/OTRLib/blob/master/Src/OTR/OTRUtilities/DSASigner.cs
Make the class public and call without constructor parameters.
var signer = new DSASigner();
var _des_key_object = signer.GetDSAKeyParameters();
Later reuse of the same key:
string _dsa_key_1_p = _des_key_object.GetHexParamP();
string _dsa_key_1_q = _des_key_object.GetHexParamQ();
string _dsa_key_1_g = _des_key_object.GetHexParamG();
string _dsa_key_1_x = _des_key_object.GetHexParamX();
// This can be a JSON for storing.
var keysArray = new string[] { _dsa_key_1_p, _dsa_key_1_q, _dsa_key_1_g, _dsa_key_1_x };
_des_key_object = new DSAKeyParams(_des_key_objectJson[0], _des_key_objectJson[1], _des_key_objectJson[2], _des_key_objectJson[3]);

Categories