Elliptic curve digital signature formats - signature

There is app built on Java library github/esig/dss and goal is to add remote signatures to PDF files.
Different methods create different formats of signatures. How to convert between them? Especially how to convert pkcs11 format to ASN1?
If PKCS11 is used with smart card then sha256 hash 53EDC760B7A66E1F4D8B0C5715725EE447B79C02F7759C52AD3D36EADD29C10A produces signature like 3066023100ba193a7a87666ebd0f923b7368beeb536b88de47834049d3ed3baf70a23635ac9b73f671beef944b36332754a434f9de023100d4984ef9f4ef61eec28f73cee6f5d8f7a391420c8f21fcc018641f5b54f600458f2d2f823e632ab017fa041e58d48a3f using algorithm ECDSA_SHA256
This is proper ASN1 structure
$ openssl asn1parse -inform der -in signature.bin
0:d=0 hl=2 l= 102 cons: SEQUENCE
2:d=1 hl=2 l= 49 prim: INTEGER :BA193A7A87666EBD0F923B7368BEEB536B88DE47834049D3ED3BAF70A23635AC9B73F671BEEF944B36332754A434F9DE
53:d=1 hl=2 l= 49 prim: INTEGER :D4984EF9F4EF61EEC28F73CEE6F5D8F7A391420C8F21FCC018641F5B54F600458F2D2F823E632AB017FA041E58D48A3F
However creating signature from CLI using pkcs11-tool the signature length is different so its in different format. How to convert this format to ASN1 der format?
$ echo "53EDC760B7A66E1F4D8B0C5715725EE447B79C02F7759C52AD3D36EADD29C10A" |pkcs11-tool -s --slot 1 -p <PIN> |xxd -p -c96
Using signature algorithm ECDSA
3f8c7060430cae99a048618035548bb7449fd9795cad2d8b3b8888fff78593da79cf39a41314a832dd8bae0b5f86c165775fcee045a477809fa8bb3245330abec22443aa8b5bccb775c32238eda1e8ce31a2a84d67b58dc9e3697c3eb8497f43

After some more research I found the answer from the BouncyCastle library. byte[] signature is RS encoded signature and the return value will be ASN.1 encoded signature.
static byte[] concatenatedRSToASN1DER(final byte[] signature, int signLength) {
int len = signLength / 2;
int arraySize = len + 1;
byte[] r = new byte[arraySize];
byte[] s = new byte[arraySize];
System.arraycopy(signature, 0, r, 1, len);
System.arraycopy(signature, len, s, 1, len);
BigInteger rBigInteger = new BigInteger(r);
BigInteger sBigInteger = new BigInteger(s);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
DERSequenceGenerator seqGen = new DERSequenceGenerator(bos);
seqGen.addObject(new ASN1Integer(rBigInteger.toByteArray()));
seqGen.addObject(new ASN1Integer(sBigInteger.toByteArray()));
seqGen.close();
bos.close();
} catch (IOException e) {
throw new RuntimeException("Failed to generate ASN.1 DER signature", e);
}
return bos.toByteArray();
}

Related

Decode value of base64 string in different language gives different output

I have a base64 string like this
String value = "fefWUeQvPgBe/9QaG/RdPnn9PrzQK2VhVwBzAIr7eei9PQrZA2/sXTA/2SCodnTSJn4Lk+ve5kuPGjco4ljYrjNTsrKBAjN6APSHn0BqBce2lOZbm/z29U6j7j79niPbYl/UIc0VTjc0IgRhmNLn1eVvMTuoaGhlwlxUf/+xenC4NmEM2A6y5/DNRheNw6OrmHik/kowpWGQsRNFyXJ2VtzE54nqs9naePBkRlWna/oqBxzA/txtHXn8h/9xTT2caozcU5/R9JayFZq7ZeclzGs2DAACr1TyQwEb9JJpBXr04Zu4rlWLtnSbyflyK3lnSAocma0L6ENnCZoMiN8gUg=="
I used this method to decode string in java
Base64Utils.decode(value.getBytes())
output:125,-25,-42,81,-28,47,62,0,94,-1,-44,26,27,-12,93,62,121,-3,62,-68,-48,43,101,97,87,0,115,0,-118,-5,121,-24,-67,61,10,-39,3,111,-20,93,48,63,-39,32,-88,118,116,-46,38,126,11,-109,-21,-34,-26,75,-113,26,55,40,-30,88,-40,-82,51,83,-78,-78,-127,2,51,122,0,-12,-121,-97,64,106,5,-57,-74,-108,-26,91,-101,-4,-10,-11,78,-93,-18,62,-3,-98,35,-37,98,95,-44,33,-51,21,78,55,52,34,4,97,-104,-46,-25,-43,-27,111,49,59,-88,104,104,101,-62,92,84,127,-1,-79,122,112,-72,54,97,12,-40,14,-78,-25,-16,-51,70,23,-115,-61,-93,-85,-104,120,-92,-2,74,48,-91,97,-112,-79,19,69,-55,114,118,86,-36,-60,-25,-119,-22,-77,-39,-38,120,-16,100,70,85,-89,107,-6,42,7,28,-64,-2,-36,109,29,121,-4,-121,-1,113,77,61,-100,106,-116,-36,83,-97,-47,-12,-106,-78,21,-102,-69,101,-25,37,-52,107,54,12,0,2,-81,84,-14,67,1,27,-12,-110,105,5,122,-12,-31,-101,-72,-82,85,-117,-74,116,-101,-55,-7,114,43,121,103,72,10,28,-103,-83,11,-24,67,103,9,-102,12,-120,-33,32,82,
then I used this method to decode string in nodejs
Buffer.from(value, 'base64')
output:125,231,214,81,228,47,62,0,94,255,212,26,27,244,93,62,121,253,62,188,208,43,101,97,87,0,115,0,138,251,121,232,189,61,10,217,3,111,236,93,48,63,217,32,168,118,116,210,38,126,11,147,235,222,230,75,143,26,55,40,226,88,216,174,51,83,178,178,129,2,51,122,0,244,135,159,64,106,5,199,182,148,230,91,155,252,246,245,78,163,238,62,253,158,35,219,98,95,212,33,205,21,78,55,52,34,4,97,152,210,231,213,229,111,49,59,168,104,104,101,194,92,84,127,255,177,122,112,184,54,97,12,216,14,178,231,240,205,70,23,141,195,163,171,152,120,164,254,74,48,165,97,144,177,19,69,201,114,118,86,220,196,231,137,234,179,217,218,120,240,100,70,85,167,107,250,42,7,28,192,254,220,109,29,121,252,135,255,113,77,61,156,106,140,220,83,159,209,244,150,178,21,154,187,101,231,37,204,107,54,12,0,2,175,84,242,67,1,27,244,146,105,5,122,244,225,155,184,174,85,139,182,116,155,201,249,114,43,121,103,72,10,28,153,173,11,232,67,103,9,154,12,136,223,32,82
The java output is what I really want to get, why its different?
How can I correctly get decoded value in nodejs
Base64Utils.decode returns a signed 8 bit value in Java. Buffer.from returns an unsigned 8 bit value in Nodejs. While both return 8 bit (byte) values, the Java method interprets the high order bit as a negative number. Nodejs is unsigned.
var value = 'fefWUeQvPgBe/9QaG/RdPnn9PrzQK2VhVwBzAIr\
7eei9PQrZA2/sXTA/2SCodnTSJn4Lk+ve5kuPGj\
co4ljYrjNTsrKBAjN6APSHn0BqBce2lOZbm/z29\
U6j7j79niPbYl/UIc0VTjc0IgRhmNLn1eVvMTuo\
aGhlwlxUf/+xenC4NmEM2A6y5/DNRheNw6OrmHi\
k/kowpWGQsRNFyXJ2VtzE54nqs9naePBkRlWna/\
oqBxzA/txtHXn8h/9xTT2caozcU5/R9JayFZq7Z\
eclzGs2DAACr1TyQwEb9JJpBXr04Zu4rlWLtnSb\
yflyK3lnSAocma0L6ENnCZoMiN8gUg=='
buffervalue = Buffer.from(value, 'base64');
for (i=0; i < buffervalue.length; i++) {
y = buffervalue[i];
if (y > 127) {
y = -(256 - y);
}
console.log(y);
}

How to calculate Retail-MAC(Single DES Plus Final Triple DES MAC) in SCP02 (Secure channel Protocol 02) with ICV encryption?

I have seen multiple people asking for a help on C-MAC generation(Retail MAC). This question contains the answer as well.
This will help your enough time.
I have tested this function with real card and it worked fine.
Note:
One can improve the efficiency of function if like.
If you find any improvement please suggest.
Before you start work on SCP 02 with communication in Ext_Atuh as CMAC please check SCP i value.
This function supports ICV encryption for next command.
public static byte[] generateCmac(byte []apdu,byte[]sMacSessionKey,byte[]icv) throws Exception {
if(sMacSessionKey.length == 16) {
byte []temp = sMacSessionKey.clone();
sMacSessionKey = new byte[24];
System.arraycopy(temp,0,sMacSessionKey,0,temp.length);
System.arraycopy(temp,0,sMacSessionKey,16,8);
}
byte []cMac = new byte[8];
byte []padding = {(byte)0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,};
int paddingRequired = 8 - (apdu.length) %8;
byte[] data = new byte[apdu.length + paddingRequired];
System.arraycopy(apdu, 0, data, 0, apdu.length);
System.arraycopy(padding, 0, data, apdu.length,paddingRequired);
Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
Cipher singleDesCipher = Cipher.getInstance("DES/CBC/NoPadding",
"SunJCE");
SecretKeySpec desSingleKey = new SecretKeySpec(sMacSessionKey, 0, 8,
"DES");
SecretKey secretKey = new SecretKeySpec(sMacSessionKey, "DESede");
// Calculate the first n - 1 block. For this case, n = 1
IvParameterSpec ivSpec = new IvParameterSpec(icv);
singleDesCipher.init(Cipher.ENCRYPT_MODE, desSingleKey, ivSpec);
// byte ivForLastBlock[] = singleDesCipher.doFinal(data, 0, 8);
int blocks = data.length / 8;
for (int i = 0; i < blocks - 1; i++) {
singleDesCipher.init(Cipher.ENCRYPT_MODE, desSingleKey, ivSpec);
byte[] block = singleDesCipher.doFinal(data, i * 8, 8);
ivSpec = new IvParameterSpec(block);
}
int offset = (blocks - 1) * 8;
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
cMac = cipher.doFinal(data, offset, 8);
ivSpec = new IvParameterSpec(new byte[8]);
singleDesCipher.init(Cipher.ENCRYPT_MODE, desSingleKey, ivSpec);
icvNextCommand = singleDesCipher.doFinal(cMac);
System.out.println("icvNextCommand"+Utility.bytesToHex(icvNextCommand, icvNextCommand.length));
return cMac;
}
A way simpler alternative is to use Signature.ALG_DES_MAC8_ISO9797_1_M2_ALG3 (if supported by the card) to calculate retail MAC value for C-MAC in SCP02.
Note: CMAC is a message authentication code which is not used in SCP02 at all.
EDIT> For PC side consider ISO9797Alg3Mac from Bouncy Castle.

Replicating Asp.net Identity Password Hash to Chilkat

Hi I want to replicate the password hashing that is done in asp.net identity such that, the resulting value of password hashed by asp.net identity and the password hashed by Chilkat are same. Is that even possible?
In C# asp.net, we use Rfc2898DeriveBytes that does the pbkdf2 for us. How can I do the same in Chilkat?
private const int PBKDF2IterCount = 1000; // default for Rfc2898DeriveBytes
private const int PBKDF2SubkeyLength = 256 / 8; // 256 bits
private const int SaltSize = 128 / 8; // 128 bits
//[ComVisible(true)]
public string HashPassword(string password)
{
if (password == null)
{
throw new ArgumentNullException("password cannot be null");
}
// Produce a version 0 (see comment above) text hash.
byte[] salt;
byte[] subkey;
using (var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, PBKDF2IterCount))
{
salt = deriveBytes.Salt;
subkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
}
var outputBytes = new byte[1 + SaltSize + PBKDF2SubkeyLength];
Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, PBKDF2SubkeyLength);
return Convert.ToBase64String(outputBytes);
}
Currently, the parameters I am using at Chilkat are:
Function EncryptChilkat(sPassword As String) As String
Dim crypt As New ChilkatCrypt2
Dim success As Long
success = crypt.UnlockComponent("ACHIEV.CR1082018_dCrRA3zr4e1M ")
If (success <> 1) Then
Debug.Print crypt.LastErrorText
Exit Function
End If
Dim hexKey As String
Dim pw As String
pw = "pwd"
Dim pwCharset As String
pwCharset = "base64"
' Hash algorithms may be: sha1, md2, md5, etc.
Dim hashAlg As String
hashAlg = "HMCSHA1"
' The salt should be 8 bytes:
Dim saltHex As String
saltHex = "78578E5A5D63CB06"
Dim iterationCount As Long
iterationCount = 1000
' Derive a 128-bit key from the password.
Dim outputBitLen As Long
outputBitLen = 128
' The derived key is returned as a hex or base64 encoded string.
' (Note: The salt argument must be a string that also uses
' the same encoding.)
Dim enc As String
enc = "base64"
hexKey = crypt.Pbkdf2(pw, pwCharset, hashAlg, saltHex, iterationCount, outputBitLen, enc)
EncryptChilkat = hexKey
End Function
Check the binary values of both the password and the salt on both sides. Also check for trailing nulls, carriage returns, and line feeds.
Additionally, you can see which, if either, algorithm is misbehaving - I have a copy of Jither's .NET PBKDF2 implementation at my github repository including test vectors, and for your Chillkat, you can create what you need from my LibreOffice Calc sheet of PBKDF2 test vectors.
Run these through both implementations; whichever one fails is wrong.
If both succeed... then you're not giving both the same parameters.

How to find SHA1 hash?

i got interesting task at school. I have to find message which sha-1 hash lasts with my birthday example. if i was born on 4th may 1932 then the hash must end with 040532. Any suggestions how to find it out?
my solution in C#:
//A create Sha1 function:
using System.Security.Cryptography;
public static string GetSHA1Hash(string text)
{
var SHA1 = new SHA1CryptoServiceProvider();
byte[] arrayData;
byte[] arrayResult;
string result = null;
string temp = null;
arrayData = Encoding.ASCII.GetBytes(text);
arrayResult = SHA1.ComputeHash(arrayData);
for (int i = 0; i < arrayResult.Length; i++)
{
temp = Convert.ToString(arrayResult[i], 16);
if (temp.Length == 1)
temp = "0" + temp;
result += temp;
}
return result;
}
Source
Then a Random String generator:
private static Random random = new Random((int)DateTime.Now.Ticks);//thanks to McAden
private string RandomString(int size)
{
StringBuilder builder = new StringBuilder();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
return builder.ToString();
}
Source
and now you can bruteforce for your combination:
string search = "32";
string result = String.Empty;
int slen = 5;
string myTry = RandomString(slen);
while (!result.EndsWith(search))
{
myTry = RandomString(slen);
result = GetSHA1Hash(myTry);
}
MessageBox.Show(result + " " + myTry);
This would search for a Hash String ending with 32. Happy Bruteforcing :)
EDIT: found one for your example: HXMQVNMRFT gives e5c9fa9f6acff07b89c617c7fd16a9a043040532
Start generating hashes from distinct messages1.
Eventually a hash will be generated with such a property. This is not that bad to brute-force as the range is only 224 (or ~16 million) and SHA is very fast.
There is no shortcut as SHA is a one way cryptographic hash function. In particular here, SHA has the property that "it is infeasible to generate a message that has a given hash".
1 The inputs should be distinct, and a simple counter will suffice. However, it may be more interesting to generate quasi-random messages based on the birthday being sought - e.g. including the date in various forms and sentences Mad Lib style. As long as this doesn't limit the domain, such that there is no qualifying hash, it'll work just as well as any other set of source messages.

Signing a string with HMAC-MD5 with C#

I got the following HMAC key (in hexadecimal format):
52320e181a481f5e19507a75b3cae4d74d5cfbc328f7f2b738e9fb06b2e05b55b632c1c3d331dcf3baacae8d3000594f839d770f2080910b52b7b8beb3458c08
I need to sign this string:
1100002842850CHF91827364
The result should be this (in hexadecimal format):
2ad2f79111afd818c1dc0916d824b0a1
I have the following code:
string key = "52320e181a481f5e19507a75b3cae4d74d5cfbc328f7f2b738e9fb06b2e05b55b632c1c3d331dcf3baacae8d3000594f839d770f2080910b52b7b8beb3458c08";
string payload = "1100002842850CHF91827364";
byte[] keyInBytes = Encoding.UTF8.GetBytes(key);
byte[] payloadInBytes = Encoding.UTF8.GetBytes(payload);
var md5 = new HMACMD5(keyInBytes);
byte[] hash = md5.ComputeHash(payloadInBytes);
var result = BitConverter.ToString(hash).Replace("-", string.Empty);
However, I am not getting the result. What am I doing wrong?
when hashing with key HMAC md5
var data = Encoding.UTF8.GetBytes(plaintext);
// key
var key = Encoding.UTF8.GetBytes(transactionKey);
// Create HMAC-MD5 Algorithm;
var hmac = new HMACMD5(key);
// Compute hash.
var hashBytes = hmac.ComputeHash(data);
// Convert to HEX string.
return System.BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
Instead of doing this:
byte[] keyInBytes = Encoding.UTF8.GetBytes(key);
you need to convert key from a hex string to array of bytes. Here you can find example:
How do you convert Byte Array to Hexadecimal String, and vice versa?

Resources