Hi Alex, Thanks a bunch for the tip!
I managed to get the signature verification step to work. Here is my code: signature = ... # 64 bytes in P1363 format. # Load signature from Microsoft's raw format to the DER-encoded # format expected by cryptography. # # Conversion steps: # - decode public numbers as 2 big-endian octet stream; # - DER-encode public numbers. def _bin2int(backend, x): backend = backend._backends[0] i = backend._lib.BN_bin2bn(x, len(x), backend._ffi.NULL) return backend._bn_to_int(i) signature = encode_dss_signature( _bin2int(backend, signature[:32]), _bin2int(backend, signature[32:]), ) I also managed to get the CGN API-based signature verification step to work when using a Cryptography-based server to sign the payload using this piece of code: signature = ... # ASN.1 # Convert signature from the DER-encoded format used by # OpenSSL into Microsoft's raw format # # Conversion steps: # - DER-decode numbers; # - encode numbers as 2 big-endian octet streams. def int2bin(backend, i): backend = backend._backends[0] i = backend._int_to_bn(i) x = backend._ffi.new( "unsigned char[]", backend._lib.BN_num_bytes(i) ) n = backend._lib.BN_bn2bin(i, x) i = backend._ffi.buffer(x)[:n] return i r, s = decode_dss_signature(signature) signature = int2bin(backend, r) + int2bin(backend, s) (I updated my gist with the C++ client & server and the Python client & server if you want to look at the rest.) I also have related snippets that allow me to convert public & private keys to and from Microsoft's format. Now, i have full interop: I can generate a keypair, share the public key, sign and verify using both Python and C++ (both directions). However, I'm relying on cryptography internals to do this, which is definitely not desirable in the medium-long term. Know of a better way to do these conversions by relying only on public APIs? Also, I guess I'm not the only person that's going to be running into this. Any interest in adding built-in support for this in cryptography? If so, I'd be willing to put some effort into a PR. Thanks, André On Fri, Aug 12, 2016 at 7:41 AM, Alex Gaynor <alex.gay...@gmail.com> wrote: > https://stackoverflow.com/questions/20992760/understanding-bcryptsignhash- > output-signature matches your intuition: the format out of Microsoft's > function is just the two numbers concatenated together, perhaps they are > little endian instead of big endian though? > > Alex > > On Thu, Aug 11, 2016 at 1:38 PM, André Caron <andre.l.ca...@gmail.com> > wrote: > >> Hi all, >> >> I'm dealing with a C++ client & server pair that uses ECDSA to verify the >> server's identity. I'm trying to write a new Python client that will >> exchange with the server without making any changes to the server. I've >> gotten quite a bit of this in place with cryptography (the Python package >> :-), but I'm incapable of getting the Python client to verify the signature >> sent by the server and I'd like to see if you can help me out. >> >> One of the problems here is that the serialization formats seem to be >> internal to Microsoft's CNG API. For example, the public key is the raw >> output of BCryptExportKey() and the signature is the raw output of >> BCryptSignHash(). These are Microsoft APIs, so... needless to say >> cryptography doesn't "just work" with these formats. >> >> I'm pretty sure I managed to nail the key format conversion as Microsoft >> makes an obscure reference to the format[1], but I'm still having trouble >> with signatures. The blob I get as output from BCryptSignHash() has 64 >> bytes, but signatures for the same algorithm using cryptography are usually >> 70-72 bytes, so I'm confused. Cryptography's ECC signature computation >> clearly documents the format: "The signature is formatted as DER-encoded >> bytes, as specified in RFC 3279." However, Microsoft doesn't seem to >> output record an equivalent anywhere. They're usually pretty consistent >> with their APIs and storage formats, so I assume some sort of storage >> similar to the keys where we have two 32-byte octet streams in big endian >> format containing the values for R and S, but I haven't had any luck with >> this. I also know that the DER encoding for two integer fields will >> normally add 6 bytes of overhead, which gets us up to 70, but there is >> still the occasional extra 1 or 2 bytes, so I'm obviously missing something >> and may not be on the right track. >> >> [1] :https://msdn.microsoft.com/library/aa375520.aspx >> >> Anyways, I managed to extract the BCrypt* function calls from the server >> and client into a pair of C++ program the contain only the signing and >> signature verification code to reproduce the flow. The total is ~30 lines >> of C++ code on each side, plus ~400 lines wrappers for BCrypt* calls >> (resource management, error handling and links to CNG API docs). >> >> I've also written a small cryptography-based Python program that tries to >> mimic the C++ client and I cannot get that part to run. >> >> If anyone has a few minutes to spare to give my Python code a second pair >> of eyeballs, I'd really appreciate it. >> >> I've saved up all of that on this Gist: https://gist.github.com/ >> AndreLouisCaron/ab5ee411d0722a0981feceddbf5cb3d9 >> >> The gist contents are as follows: >> - genkeys.py: generate a public/private key pair, write to disk in >> Microsoft's format; >> - server.cpp: load secret key, compute signature, save payload & >> signature to disk; >> - client.cpp: load public key, payload & signature from disk, verify >> signature; >> - common.h: stuff shared by client.cpp & server.cpp; >> - client.py: same as client.cpp, but using cryptography. >> >> I also have an alternate C++ client based on OpenSSL which might be a >> better source of inspiration. I'll see if I can extract pars of that too >> as a reference since it might be easier to map to cryptography's internals. >> >> Thanks in advance, >> >> André >> >> _______________________________________________ >> Cryptography-dev mailing list >> Cryptography-dev@python.org >> https://mail.python.org/mailman/listinfo/cryptography-dev >> >> > > > -- > "I disapprove of what you say, but I will defend to the death your right > to say it." -- Evelyn Beatrice Hall (summarizing Voltaire) > "The people's good is the highest law." -- Cicero > GPG Key fingerprint: D1B3 ADC0 E023 8CA6 > > > _______________________________________________ > Cryptography-dev mailing list > Cryptography-dev@python.org > https://mail.python.org/mailman/listinfo/cryptography-dev > >
_______________________________________________ Cryptography-dev mailing list Cryptography-dev@python.org https://mail.python.org/mailman/listinfo/cryptography-dev