August 6th, 2018
Deciding that transactions were a source of complexity, and it was enough that the user could sign a string, is what prompted me to fork steem-js. In doing so, I only exposed a previously hidden routine deep inside the library.
Now, there is a routine called steem.auth.signBuffer(). When a transaction is signed a digest is created, the digest is sent to this routine and the signature is created. A recovery parameter is included so we know which square root to to give as the public key. If the public key matches tha public key that was supposedly used to sign, the signature verifies.
My change for steem-js amounts to a single non-comment line of code:
// @parameter 1 : buffer (string) // @parameter 2 : private_signing_key (string) // returns a signature of type Signature (which can be made readable with .toHex() or .toBuffer()) Auth.signBuffer = Signature.signBuffer;
Such a small amount of code should be easy to maintian.
Instead of passing the raw signature to the CGI script, the signature has to made into hex string like this:
let session_signature = steem.auth.signBuffer(session, private_signing_key); let session_signature_string = session_signature.toHex();
That was a source of some problems in retrieving the correct key!
In my Python code, I have my own customized verify_message implementation:
verify_message(session.id, session_signature, public_key)
session.id is a string, session_signature can be a 65 byte run of bytes or 130 hex string, and the public_key is actually an address of the form : STM.... This is the form of objects that you will see when streaming transactions using Steem-python or Beem.
It turns out there are similar routines to my implementation but only mine really works with the Steem notion of what a signature and a public key should be. Other implementations do not expect a 65 byte signature or keys that start with STM or STX. Mine does.
Here is Steem-specific verify_message routine implemented in beem:
# Verify a message has signature message_signature with address address. # If this verifies the routine returns nothing at all, but it it doesn't an exception is thrown. def verify_message(message: str, signature: str or bytes, address : str): if not isinstance(message, bytes_types): message = py23_bytes(message, "utf-8") if not isinstance(signature, bytes_types): signature = py23_bytes(signature, "utf-8") if not isinstance(message, bytes_types): raise AssertionError() if not isinstance(signature, bytes_types): raise AssertionError() if len(signature) == 130: signature = binascii.unhexlify(signature) if len(signature) != 65: raise AssertionError() digest = hashlib.sha256(message).digest() sig = signature[1:] recover_parameter = (bytearray(signature) - 27) % 4 # recover parameter only uncompressed_public_key = beemgraphenebase.ecdsasig.recover_public_key(digest, sig, recover_parameter) # Will throw an exception if not valid uncompressed_public_key.verify_digest( sig, digest, sigdecode=ecdsa.util.sigdecode_string ) phex = beemgraphenebase.ecdsasig.compressedPubkey(uncompressed_public_key) recovered_public_key = beemgraphenebase.account.PublicKey(binascii.hexlify(phex).decode("ascii")) if format(recovered_public_key, address[0:3]) != address: raise Exception("Incorrect supplied key or message")
Journal Entry List
- August 6th : Sign in Steem-JS, verify in Beem!
- July 9th Public Key Cacheing in Steemfiles
- June 23rd Signing vs. Shared Secrets
- March 15th Developing Keybox, a signer, and a broadcaster
- March 14th (Working on a new Wallet
- March 13th (importance of source control, showing Public Keys, Politics Utopian)
- March 12th (keyring package for python) listing)
- March 10th (Keybox full working source code listing)
- March 9th
- March 8th
Bitcoin 1Q1WX5gVPKxJKoQXF6pNNZmstWLR87ityw (too expensive to use for tips)