I have signed a hash value in windows using BCryptSignHash with ECDSA algorithm. The output signature buffer is of length 64 bytes. I also generated the public and private key blobs using BCryptGenerateKeyPair function (BCRYPT_ECDSA_P256_ALGORITHM algorithm) with which i signed the hash.
I have to verify this signature with this key pair in linux. I am able to decipher the public-private key pair that got generated, using the link "http://msdn.microsoft.com/en-us/library/windows/desktop/aa375520%28v=vs.85%29.aspx" and able to use the same in linux.
The 64-byte signature generated should ideally be signature pair (r,s) (http://en.wikipedia.org/wiki/Elliptic_Curve_DSA).
Is there a way to understand the 64-bytes signature generated so that i can map the signature blob contents to (r,s) pair in linux and verify it?
Or is there a simpler way to verify the generated signature in linux?
Thanks,
F
Is there a way to understand the 64-bytes signature generated so that I can map the signature blob contents to (r,s) pair in linux and verify it?
The r and s are in P1363 format, which is simply a concatenation of r and s in a 2's compliment format. That is, the signature is simply r || s.
You need to know the hash to use this format. For example, SHA1 will create a r of 20 bytes and an s of 20 bytes. If r or s is "too short", then it is padded on the left with 0's.
Java and OpenPGP are different than P1363. Java and OpenPGP use an ASN.1 encoding:
SEQUENCE ::= {
r INTEGER,
s INTEGER
}
Depending what library you use on Linux, you may have to convert between the formats. Cryptographic Interoperability: Digital Signatures gives examples of signing and verifying using a few different libraries.
Or is there a simpler way to verify the generated signature in linux?
Try Crypto++. I believe Microsoft and Crypto++ uses the same signature format, so you won't need to convert. See Elliptic Curve Digital Signature Algorithm for details.
Related
I implemented ECDSA manually in rust, where the output is signature in the form of a tuple (r,s). I wanted to test my implementation, and therefore I was looking for functions in python or rust for verifying the signature (r,s) given the public key, message and the curve details. The Wiki article also shows the output signature in tuple form.
But, everywhere I looked, the signature is inputted as a single hex string or a byte array. Can someone please share any way of converting (r,s) pair to the hex string. I tried concatenation but got wrong result in my algo.
If it is helpful, I tried using the crate secp256k1 in rust for verification.
I'd like to derive an elliptic curve private key from input keying material (a master key). Is this possible?
Attempts
Node's crypto function, crypto.generateKeyPair does not accept input keying material, and crypto.createPrivateKey only converts a .pem to Node's native KeyObject.
I also can't find a way to do this in OpenSSL using ecparam. The -rand flag seems promising but isn't widely available (it's not on my machine).
Why / Details
I need to create a number of secrets and want have all of them derived from a single master key. This is analogous to HKDF.
I'm using the keys for ECDSA with curve P-384 (secp384r1).
I'm surprised you think ecparam -rand file -genkey ... is rare; it's in every upstream version back at least to 0.9.8 in 2005, and it's not one of the things that can be omitted by a build (configure) option, so your machine must have one weird version. But it doesn't matter because -rand doesn't do what you want; it adds the file data to the RNG 'pool' but does not replace it, so it doesn't give you deterministic key generation.
As Woodstock commented, for all practical purposes a raw P-384 private key is just 384 bits from any good random generator, or deterministically from any uniform random function. Technically you should exclude zero and values greater than or equal to the (sub)group order n, but those exclusions are so small relative to 2^384 that there is essentially no chance a good random choice will hit them during the lifetime of the Earth, and perhaps of the universe. You might want to look at how Bitcoin 'hierarchical deterministic' key derivation aka BIP 32 works, although of course that does 256-bit keys for secp256k1.
That leaves you the problem of converting the raw key to a form usable by nodejs crypto (which is a fairly thin wrapping of openssl library) and/or openssl commandline. To do this follow the principles of How to convert an ECDSA key to PEM format which is in turn based on https://bitcoin.stackexchange.com/questions/66594/signing-transaction-with-ssl-private-key-to-pem except use the OID and size(s) for P-384 instead of secp256k1. Specifically, concatenate
the 7 bytes represented in hex by 303e0201010430
the 48 bytes (384 bits) of the raw private key
the 9 bytes represented in hex by a00706052b81040022 (for P-384 aka secp384r1)
Depending on your language(s) or tool(s) you might handle these values directly, or concatenate the hex representations and then convert to binary. The result is the 'DER' (binary) form of the algorithm-specific (SEC1) private key (only), which can be read by nodejs 11 or 12 crypto.createPrivateKey( {key:(data), format:'der', type:'sec1'} ) and also by commandline openssl ec -inform der.
If you prefer textlike things (e.g. for cut&paste), convert the DER above to base64, break into lines of 64 chars (other than the last), and add lines -----BEGIN EC PRIVATE KEY----- before and -----END EC PRIVATE KEY------ after. This is PEM format and can be read by createPrivateKey without any other options, and by openssl ec without any option.
If I have a payload, signature, and a public key (all in bytestring or similar format), how can I verify the signature?
All of the PublicKey types I see on Hackage seem to represent keys purely via numbers, for instance:
PublicKey
public_size :: Int -- size of key in bytes
public_n :: Integer -- public p*q
public_e :: Integer -- public exponant e
How can I get a PublicKey from a PEM file, or simply perform verification directly from the PEM file?
[EDIT from the feedback that no solution attempt was made] - I looked around for solutions, but haven't been able to find anything at all on hoogle that satisfies any type signature I'd expect, like ByteString -> PublicKey. I don't want to reimplement this from scratch, as what I'm doing now is just calling out to a python script that performs all of the verification. It would be nice if I didn't need to call out to python though, but can't seem to find any existing code.
If a library exposes an interface like public_n :: Integer, it means that it's a library that illustrates the RSA operation, not a library for cryptography. A cryptography library would have interfaces like sign :: Key -> ByteString -> ByteString. Any cryptography library should be able to parse keys in PEM format.
OpenSSL is a popular library for cryptography. It isn't always ideal or easy to use, but it's widespread, and you won't be using its quirky C interface since you're using Haskell. So you can use HsOpenSSL, which is a Haskell binding over OpenSSL. (Note: I have never used HsOpenSSL, but it looks sensible.) Use OpenSSL.PEM.readPrivateKey to read a key in PEM format, OpenSSL.EVP.Digest.digestLBS to calculate a digest of the message you want to sign, and OpenSSL.EVP.Sign.signBS to sign the digest.
I need to sign a small string with an asymmetric key encryption scheme.
The signature will be stored on a small chip together with the signed string. I have very little space to spare (about 60bytes for signature + string), so the generated signature should be as small as possible.
I looked around for how to do it, and what I found is that I could use RSA-SHA1, but the generated signature with a 512 bit key is 64 bytes. That is a bit much.
What secure algorithm could I use to generate a small asymmetric signature?
Would it still be secure if I store the SHA1 sum of the RSA-SHA1 signature, and later verify that instead?
What you're bumping up against here is one of the properties of a good hash function - the return value should be long to protect against birthday attacks (where two different inputs result in the same output hash). Generally 128-512 bits is preferred hence the SHA-1 signature gives you 512 bits.
As with all things in cryptography security is a trade off. As you are using asymmetric signing have you considered using RSA-MD5 as your signature option? This will give you a far shorter return of 128 bits but this comes with the caveat that MD5 is considered broken and is generally being moved away from.
I would like to sign a device, and I have 64 bits to store my signature in the device. This device has a MAC address and some other details (about 30 bytes worth) I can mangle to create my signature.
If possible, I would like the method to be one-way, so that I can verify that the signature is valid without knowing how to create a valid signature. Most public-private keys have this feature but they generate signatures that are 48 bytes long (I only have 8 bytes).
Implementation in Python is a plus.
Thanks
EDIT:
Thanks for the advice everyone. It sounds like there is no secure way to do this, only a way that is moderately inconvenient to attackers. I'll probably use a cryptographic hash combined with secret bit-shuffling. This will be as secure as any other link in my (very weak) 'security'.
Hash functions and digital signatures are very different things.
The size of a digital signature depends on the underlying hash function and the key length. So in theory, you can create an RSA implementation that generates 64-bit signatures, but that'd be an extremely weak signature.
For smaller key lengths, you might want to look at elliptic curve cryptography.
EDIT: Yes, I'm a cryptographer.
EDIT 2: Yet if you only need a hash function, you can look at elf64 or RIPEMD-64 as Fernando Miguélez suggested.
EDIT 3: Doing the math, you'd need to use 16-bit keys in ECC to generate 64-bit signatures, which is very weak. For ECC, anything less than 128 bits can be considered weak. For RSA this is 1024 bits.
Basically what you need is a 64-bit cryptographic hash funcion, such as Ripemd-64 or elf-64. Then you encrypt the hash with a cryptographic method and you got a 64 bit signature. The only problem is, from the point of view of a non-cryptoanalyst, that 64 bit offers a much weaker signature than typical over-128 bit hash. Nonetheless it could still be suitable for your application.
You could just use a standard hashing function (MD5 SHA1) and only use the first or last 30 bytes.
The number of bytes a hashing function generates is fairly arbitrary - it's obviously a trade off between space and uniqueness. There is nothing special about the lenght of the signature they use.
Edit - sorry I was thinking that MD5 returned 32bytes- it actaulyl returns 16bytes but is ussually written as 32hex digits.