Author

Topic: [BOUNTY: 2.0 BTC] [CLAIMED] Message Signing in Armory (Read 8004 times)

full member
Activity: 123
Merit: 100
Found a bug in the FormatText() method. Easy fix:

This line:

Code:
      while len(l) and l[len(l)-1] in [' ', '\t', chr(9)]:

Should include '\r':

Code:
      while len(l) and l[len(l)-1] in [' ', '\r', '\t', chr(9)]:

Without this it fails to strip spaces from the ends of lines terminated with '\r\n'
full member
Activity: 123
Merit: 100
Excellent! Thanks for the confirmation. That's what I ended up doing. Now I can be sure that's the correct solution.
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
JackJack,


I'm reviewing the dash-escape code in jasvet.py, and I'm unsure whether the code in FormatText() follows rfc2440 exactly:

Quote
Dash escaped cleartext is the ordinary cleartext where every line
starting with a dash '-' (0x2D) is prefixed by the sequence dash '-'
(0x2D) and space ' ' (0x20).

The I way interpret this is that ".../n/r-some text..." would be displayed as ".../n/r- -some text..." but FormatText() returns ".../n/r- some text...".

The latter seems better because it's one character closer to the original and achieves the same purpose.

However, I'm concerned that someone might used Armory to verify a message that is cleartext signed by a different application and yield an incorrect response.

Do you think that this is a valid concern? Do you know of any other rfc2440 implementations that indicate which way is correct?
Indeed it seems I understood that the wrong way

I thought the '-' of the line was not part of the prefixed thing, I didn't find any examples of implementations but the rfc is clear enough:
Quote
every line starting with a dash is prefixed
That means the dash is actually part of what is prefixed

Thank you for bringing this to my attention
I'll fix that soon, in the mean time you just have to replace line 506:
from
Quote
l='- '+l[1:]
to
Quote
l='- '+l
full member
Activity: 123
Merit: 100
JackJack,


I'm reviewing the dash-escape code in jasvet.py, and I'm unsure whether the code in FormatText() follows rfc2440 exactly:

Quote
Dash escaped cleartext is the ordinary cleartext where every line
starting with a dash '-' (0x2D) is prefixed by the sequence dash '-'
(0x2D) and space ' ' (0x20).

The I way interpret this is that ".../n/r-some text..." would be displayed as ".../n/r- -some text..." but FormatText() returns ".../n/r- some text...".

The latter seems better because it's one character closer to the original and achieves the same purpose.

However, I'm concerned that someone might used Armory to verify a message that is cleartext signed by a different application and yield an incorrect response.

Do you think that this is a valid concern? Do you know of any other rfc2440 implementations that indicate which way is correct?
full member
Activity: 123
Merit: 100
Thanks. Just pulled it. I'm sure something else will break before this reaches it's limit.
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
The new version is online, I tested only with a message of 400 characters but it should be ok

You're not duplicating anything (sadly)
I think the readme is clear enough but tell me if you have trouble parsing things
full member
Activity: 123
Merit: 100
That's great, and thanks for the speedy response.

Also, I am parsing out the signature and message from the ASv1B64 and ASv1CS outputs to pass into verifySignature. Please let me know if that is included in the latest version. No problem if it's not, I just don't want to duplicate any of your code.
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
I thought I fixed that before releasing the code!
Sorry for that, I'll push an update in the following minutes
full member
Activity: 123
Merit: 100
JackJack,

I am integrating the message signing code you provided into Armory. I am looking at this function:

Code:
def format_msg_to_sign(msg):
   return "\x18Bitcoin Signed Message:\n"+chr(len(msg))+msg  #todo: check 18

It seems to limit the length of the message to 255 characters.

Can we do longer messages using a var int? Is 255 the intended limit?
legendary
Activity: 2126
Merit: 1001
All right, now I'm totally lost.

I used as a privkey:
Quote
5JVNazqC4JucAHUeRLhcqrbGFAro2CySd2ptDaDnPe18G9tmuAs

Message:
Quote
Hello world!

And got as a signature from jasvet.py:
Quote
IHBIv6b+gp+aX1FSQ9vOGfjbh6svVfRzLq2NBlwSu6xQE7sq2cWBQnbRwkOL64IkJguDELeh9nGXKmlHxFgKJiI=

Now comes the funny part:
Both http://brainwallet.org/#verify and bitcoin-qt do verify the signature, but only to the adress
Quote
1N8UThyPpVz8DuZLNx4KbX9rqQhFAFfGRE

The proper pubkeys to the given privkey should be:
uncompressed:
1E4PLo2YV33dkG7np78rz3aT3yTQvK7Xkz
compressed:
1D6eGU1hudNTkg5eaqYHxgM3NYCbq6MJoy

What the heck is this mystery adress?

As reference, from http://brainwallet.org/#sign I got
Quote
HMkg8LsNsYAC/oTEbgaBZy6kLNjLPSz1cZbCcqlFAL6GqdxRGR2LEg6PofSnpkFVlJTPqFS0amps9t55WBcToNo=
and from bitcoin-qt
Quote
HPM/8W8EhvKMrBfY0X9TrHx8UJQNTl1XBrzH/63jZSoc4tByiOr5U9wkn4KJ8cWKDjF9PJFRl/Kb121OqOq0jQQ=
as signatures, which both are verified valid by the respective other as coming from 1E4PLo2YV33dkG7np78rz3aT3yTQvK7Xkz, the uncompressed adress.


Is there a different way to do this (signing a text with the privkey, being able to verify it with the pubkey) resulting in an even shorter signature? Doesn't have to be Bitcoin-related at all. Some recognized standard would be nice, so I don't have to print the sourcecode to the backside ;-)

Ente

Bump.
Did anyone observe similar symptoms?

Ente
legendary
Activity: 1593
Merit: 1004
If you want to still use it:  click the address book icon above the message box in the bottom left.  Select the address you want.  Put your message in the box.  Then click "Sign" and type in your passphrase when it asks.  Once the signature is present, you can click "Copy Signature Block."   You can immediately "Import Signature Block" to test it. 

As I said, it's not really made to be used, right now.  But the next version will have it.

It's simply not asking me for my passphrase when I click "Sign Message". It either crashes or fails to create a signature Sad

Me too.  Really disappointed I'll have to go back to Qt.  I really like Armory's layout and all.  Feel better about it's security.  But I have to have signed messages.  Many transactions demand it.
sr. member
Activity: 299
Merit: 250
If you want to still use it:  click the address book icon above the message box in the bottom left.  Select the address you want.  Put your message in the box.  Then click "Sign" and type in your passphrase when it asks.  Once the signature is present, you can click "Copy Signature Block."   You can immediately "Import Signature Block" to test it. 

As I said, it's not really made to be used, right now.  But the next version will have it.

It's simply not asking me for my passphrase when I click "Sign Message". It either crashes or fails to create a signature Sad
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
Can someone please explain to me the procedure for signing messages in Armory? I simply can't seem to generate a signed message block using the method described here: https://bitcointalksearch.org/topic/signing-messages-in-armory-252848

It's crappy.  It was originally a key calculator, with signing as an after-thought.  When it turned out that so few people found it useful (since it wasn't compatible) I stopped doing anythign on it until I had a chance to upgrade it to a compatible one (and isolate message signing from the other stuff).

If you want to still use it:  click the address book icon above the message box in the bottom left.  Select the address you want.  Put your message in the box.  Then click "Sign" and type in your passphrase when it asks.  Once the signature is present, you can click "Copy Signature Block."   You can immediately "Import Signature Block" to test it. 

As I said, it's not really made to be used, right now.  But the next version will have it.
sr. member
Activity: 299
Merit: 250
Can someone please explain to me the procedure for signing messages in Armory? I simply can't seem to generate a signed message block using the method described here: https://bitcointalksearch.org/topic/signing-messages-in-armory-252848
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
That is the intention.  Unless I misunderstood you.  The goal isn't "This message has a valid signature!"  It's "This message has a valid signature from address 1xyZaQb".  Or rather: "This message has been signed by the same person who sent you 42.83 BTC yesterday."  If you have previously transacted with someone, then you know what address you're looking for.  I agree, it's easy to be misused/misunderstood by people who don't understand what they're doing, but that also doesn't mean it's useless. 

The use cases I imagined were anonymous, paid services.  You can use signed messages from the funding address to authorize requests to your account with that service.  They don't care who you are, they only care that the same person that funded that account is signing the message.

Am I missing something? 
staff
Activity: 4284
Merit: 8808
The user should have no idea what's in it until they copy it into their wallet and it will spit out the message only if the signature is valid.  This is considered ideal since users have a tendency to only look for the message header and trust it without checking.  This way, they can't get the message unless they also check the signature.
uh. You realize you can't have what you want here without building a PKI, right?  I mean, you can make them push a button, but all signatures will pass (except where the attacker is incompetent).

The way signmessage was designed in Bitcoin you have to provide both the message you expect to be signed and the address you expect to have signed it... so that the validation passing isn't just tautological— a ritual that just fulfills itself and always returns true—, but actually means indicates that the user's inputs were consistent.

It helps if you actually understand the use-case for signmessage in Bitcoin-QT:  It's used as an authentication mechanism for services which are address based, e.g. for changing configurations settings on the eligius pool, and it was informed by a number of security exploits against openpgp based systems (e.g. some of the ripe address record databases) which allowed any user to impersonate any other user because gpg --validate would pass on all of them, but there was no way to tell it what user was actually required, so any in your keyring would pass.
legendary
Activity: 2126
Merit: 1001
All right, now I'm totally lost.

I used as a privkey:
Quote
5JVNazqC4JucAHUeRLhcqrbGFAro2CySd2ptDaDnPe18G9tmuAs

Message:
Quote
Hello world!

And got as a signature from jasvet.py:
Quote
IHBIv6b+gp+aX1FSQ9vOGfjbh6svVfRzLq2NBlwSu6xQE7sq2cWBQnbRwkOL64IkJguDELeh9nGXKmlHxFgKJiI=

Now comes the funny part:
Both http://brainwallet.org/#verify and bitcoin-qt do verify the signature, but only to the adress
Quote
1N8UThyPpVz8DuZLNx4KbX9rqQhFAFfGRE

The proper pubkeys to the given privkey should be:
uncompressed:
1E4PLo2YV33dkG7np78rz3aT3yTQvK7Xkz
compressed:
1D6eGU1hudNTkg5eaqYHxgM3NYCbq6MJoy

What the heck is this mystery adress?

As reference, from http://brainwallet.org/#sign I got
Quote
HMkg8LsNsYAC/oTEbgaBZy6kLNjLPSz1cZbCcqlFAL6GqdxRGR2LEg6PofSnpkFVlJTPqFS0amps9t55WBcToNo=
and from bitcoin-qt
Quote
HPM/8W8EhvKMrBfY0X9TrHx8UJQNTl1XBrzH/63jZSoc4tByiOr5U9wkn4KJ8cWKDjF9PJFRl/Kb121OqOq0jQQ=
as signatures, which both are verified valid by the respective other as coming from 1E4PLo2YV33dkG7np78rz3aT3yTQvK7Xkz, the uncompressed adress.


Is there a different way to do this (signing a text with the privkey, being able to verify it with the pubkey) resulting in an even shorter signature? Doesn't have to be Bitcoin-related at all. Some recognized standard would be nice, so I don't have to print the sourcecode to the backside ;-)

Ente
legendary
Activity: 2126
Merit: 1001
Signatures aren't unique Smiley

OH! Of course, without ever thinking about it, I assumed those signatures would be unique! Maybe like a hash with several inputs, one being the privkey and the other being the text.

All right, but even when several different signatures verify "true" to the same adress and text, they all should verify.
I can't figure how to verify

Quote
{'b64-signature': 'ICJNavINw/4nHQId8M6AZ+IyyugUSwdp0RcVbUH+jknO5liYIiv5LolCFOZZSSTOySYasEL8f/hak6poxgB+DmI=', 'message': 'Hello world!', 'signature': ' "Mj\xf2\r\xc3\xfe\'\x1d\x02\x1d\xf0\xce\x80g\xe22\xca\xe8\x14K\x07i\xd1\x17\x15mA\xfe\x8eI\xce\xe6X\

on http://brainwallet.org/#verify

Privkey:
Quote
5KWLD8VF29WR36qR2YM3wWLDuePHJAP4YKgCMcfvNN7TTxSFgFx
Text:
Quote
Hello world!
Pubkey:
Quote
1PRPcHe3fFGjLmaGWFbQ92FtjKuSoUgcyz

I'll dig out bitcoin-qt in a minute, and try to get some result which two out of the three agree upon ;-)

/edit:

Aww man, of course now it works!
Quote
ICJNavINw/4nHQId8M6AZ+IyyugUSwdp0RcVbUH+jknO5liYIiv5LolCFOZZSSTOySYasEL8f/hak6poxgB+DmI=
Quote
Hello world!
Verifies to
Quote
16RiJy3VBjf4bQJiF5UL887pggK1RasMn8

Thank you, jackjack, for the script! Will have some fun with it now! :-)

Ente
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
Signatures aren't unique Smiley
legendary
Activity: 2126
Merit: 1001
I just played a bit with jasvet.py, thank you both, jackjack and Alan.

I try to sign one same message with several addresses. The signature should be somewhat futureproof and "official"
(Like, legally proving the ownership of several addresses).
A short signature is a plus, to be able to queeze more onto one piece of paper.

So, I figured I'll go with the bitcoin-qt v0 method for this.

Adding this to the script:
Code:
def DecodeBase58Check(sec):
vchRet = b58decode(sec, None)
secret = vchRet[0:-4]
csum = vchRet[-4:]
hash = Hash(secret)
cs32 = hash[0:4]
if cs32 != csum:
return None
else:
return secret

#==============================================

pvk1=DecodeBase58Check("5KWLD8VF29WR36qR2YM3wWLDuePHJAP4YKgCMcfvNN7TTxSFgFx")
text1='Hello world!'
FTVerbose=True
sv0=ASv0(pvk1, text1)
print sv0

jasvet.py says:
Quote
{'b64-signature': 'ICJNavINw/4nHQId8M6AZ+IyyugUSwdp0RcVbUH+jknO5liYIiv5LolCFOZZSSTOySYasEL8f/hak6poxgB+DmI=', 'message': 'Hello world!', 'signature': ' "Mj\xf2\r\xc3\xfe\'\x1d\x02\x1d\xf0\xce\x80g\xe22\xca\xe8\x14K\x07i\xd1\x17\x15mA\xfe\x8eI\xce\xe6X\

It seems I got something wrong, or need to convert the output or the like.

http://brainwallet.org/#sign says:

Privkey:
Quote
5KWLD8VF29WR36qR2YM3wWLDuePHJAP4YKgCMcfvNN7TTxSFgFx

Text:
Quote
Hello world!

Signature:
Quote
G+xTV1JL0C3eAtIPQwOETWwKYCALDR2Px0u1S/4CXl1lKhM/0mFEsuYH2BVMlPe/FvJFJmuFue2TfWW8OgacBVo=


Ah, it's no fun to be a noob, I can tell ya!  Cheesy

Ente
legendary
Activity: 1258
Merit: 1001
There is a webpage which can do the work for you
http://brainwallet.org/#sign
You need to provide your private key (u can get it on the SIGN MESSAGE window of armory by selecting the address using address button)
This runs on java script - so your private key wont get sent to any web server
The point is precisely not to use another software but rather having everything done in Python
I do agree. But this is just for people who wish to sign a message but are using armory. I had to spend lot of time to figure this out as needed to sign some message. I hope it helps someone Smiley
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
There is a webpage which can do the work for you
http://brainwallet.org/#sign
You need to provide your private key (u can get it on the SIGN MESSAGE window of armory by selecting the address using address button)
This runs on java script - so your private key wont get sent to any web server
The point is precisely not to use another software but rather having everything done in Python
legendary
Activity: 1258
Merit: 1001
There is a webpage which can do the work for you
http://brainwallet.org/#sign
You need to provide your private key (u can get it on the SIGN MESSAGE window of armory by selecting the address using address button)
This runs on java script - so your private key wont get sent to any web server
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
I have an armory wallet and need to sign a message to prove ownership of a particular address to recover scammed funds. I'm running the MacOSx. Is the message signing compatible with bitcoin-qt yet? If so, How do I sign in this method? I currently tried verifying a signed message and it failed in bitcoin-qt.

Thank you!
I don't think etotheipi already put the code in Armory (I can be wrong though)
If you have python on your OSX I can make tweak my code a bit to do what you want until it's implemented
hero member
Activity: 714
Merit: 500
champion! thanks
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
1.
You need to add that function:
Code:
def DecodeBase58Check(sec):
vchRet = b58decode(sec, None)
secret = vchRet[0:-4]
csum = vchRet[-4:]
hash = Hash(secret)
cs32 = hash[0:4]
if cs32 != csum:
return None
else:
return secret

pvk1=DecodeBase58Check("5KWLD8VF29WR36qR2YM3wWLDuePHJAP4YKgCMcfvNN7TTxSFgFx")

2.
Code:
pubkey = EC_KEY(pvk1, bool(compressed key or not?)).pubkey  #this is an object
pbk = pubkey.ser()   #the serialization itself: 04+x+y or 02+x or 03+x
hero member
Activity: 714
Merit: 500
I just released on github before your message: https://github.com/jackjack-jj/jasvet/blob/master/jasvet.py

Im trying to make a quick and dirty script to sign messages that are compatible with Bitcoin & Armory clients and came across your nicely written Python module .

Just wondering if you could give me a couple of pointers to get me started

Quote
#
#  Some tests with ugly output
#  You can delete the print commands in FormatText() after testing
#

pvk1='\x01'*32


text0='Hello world!'


FTVerbose=True
sv0=ASv0(pvk1, text0)
print sv0
verifySignature(sv0['address'], sv0['b64-signature'], sv0['message'])
print
print ASv1B64(pvk1, text0)
print
print ASv1CS(pvk1, text0)

How can I get a representation of my private key from base58 format (e.g. 5KWLD8VF29WR36qR2YM3wWLDuePHJAP4YKgCMcfvNN7TTxSFgFx) so I can plug it into `pvk1` ?

Can I just do the following ...

Quote
pvk1 = b58decode('5KWLD...', None)

Secondly, how can I calculate the public key from pvk1?

cheers!



hero member
Activity: 547
Merit: 500
Decor in numeris
Ahh.  You know I never used easy_install, but I just tried it.  That really is easy! 


At least until you want to uninstall again.  No luck.  Which is why pip is preferred over easy_install, and preferably in a virtual_env.
Care to explain? I never heard anything about that

unlike real packaging systems, easy_install drops everything in the main Python directory structure.  There is no central database of what was installed by which package, and no way to uninstall the stuff again.  This can make it kind of hard to return to a clean installation, or to get rid of unnecessary packages.
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
Ahh.  You know I never used easy_install, but I just tried it.  That really is easy! 


At least until you want to uninstall again.  No luck.  Which is why pip is preferred over easy_install, and preferably in a virtual_env.
Care to explain? I never heard anything about that
hero member
Activity: 547
Merit: 500
Decor in numeris
Ahh.  You know I never used easy_install, but I just tried it.  That really is easy! 


At least until you want to uninstall again.  No luck.  Which is why pip is preferred over easy_install, and preferably in a virtual_env.

legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
As etotheipi asked me I just pushed a new version, which doesn't need any dependency
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
Thanks
I think it's easily tweakable. If anybody (etotheipi or any reader in the future) got a problem, just PM me or complain here!
legendary
Activity: 1072
Merit: 1181
Just as a FYI, the C secp256k1 library I'm writing has support for creating recoverable signatures, and doing key recovery (though not the - admittedly weird - serialization that Bitcoin uses for it).
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
easy_install ecdsa must work
I'm sure I can get rid of that dependency though

Ahh.  You know I never used easy_install, but I just tried it.  That really is easy! 

Okay, it works now.  I might have to dig in a little bit to tweak things.  But it looks like exactly what I wanted.  PM me a payment address.
Thanks jackjack!
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
easy_install ecdsa must work
I'm sure I can get rid of that dependency though
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
I changed the Readme, is it enough?

Code looks good, but I can't try it because I don't have the ecdsa module.  What/where is that?
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
I changed the Readme, is it enough?
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
Great

The CRC24 is used to check that the ASCII armor wasn't modified. So it's calculated on the data you send to base64, ie (lb+r+s) or (lb+r+s+msg)
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
As a Bitcoin signed message will always have the same, fixed format I think we don't need to use packets as they are used to provide flexibility
That would for example lead to:
  • signature = byte + r + s
  • sig+msg = byte + r + s + msg
Text rules (dash, etc...) in RFC2440 can (and should imo) be used

That way we have a simple format
Code:
lb, r, s, msg = data[0] + data[1:33] + data[33:65] + data[65:]
if msg:
  ...
else:
  ...


Or tell me what you prefer

That sounds good to me.  We want the standardized encoding/formatting, but don't need to all the flexibility in those serializations, since we have a very static/simple system for Bitcoin.  So clearsign will be identical to RFC2440 for the message, dash-esc, etc, but the signature will only be 65 bytes in base64.  The opaque version will simply be the header & footer, with the the properly-formatted message as you described above, all converted to base64. 

Where does crc24 fit into this?  Was that implemented and used?  I didn't look too closely at where it fit in.  Or was it only useful for the OpenPGP-formatted stuff?
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
As a Bitcoin signed message will always have the same, fixed format I think we don't need to use packets as they are used to provide flexibility
That would for example lead to:
  • signature = byte + r + s
  • sig+msg = byte + r + s + msg
Text rules (dash, etc...) in RFC2440 can (and should imo) be used

That way we have a simple format
Code:
lb, r, s, msg = data[0] + data[1:33] + data[33:65] + data[65:]
if msg:
  ...
else:
  ...


Or tell me what you prefer
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
I'll try to be clearer:
  • Bitcoin's base64 is base64( leading byte + r + s )
  • My current code base64 (for v0, v1CS and v1B64) is base64( leading byte + r + s )
  • RFC2440 works with packets:
    • Verifying a clear text needs only a signature packet: base64( type + length + 04 + hash algorithm byte + pubkey type byte + timestamp + ... + MPI(r) + MPI(s) )
    • Verifying with included text needs a signature packet and a literal data packet: base64( type of literal data packet + len of literal data packet + flag + 00 + timestamp + message + type of pubkey packet + length of pubkey packet + 04 + hash algorithm byte + pubkey type byte + timestamp + ... + MPI(r) + MPI(s) )

As you can see, OpenPGP doesn't contain the leading byte so anyway I can't use strict RFC2440 to concatenate sig+data
A choice must be made because we can't use strict RFC2440 rules

Understood.  It's okay to deviate from RFC2440 as long as it's documented.  The goal was simply to follow RFC2440 to standardize the implementation as much as possible, but knowing that there would be slight deviations from RFC2440 where it makes sense to use our Bitcoin conventions.  I am honestly not going to be picky about it, as long as what is chosen is well-defined and documented. 
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
Is the v1-Base64 you identified correctly?  It says "BEGIN SIGNATURE", but it should probably be "BEGINE BITCOIN MESSAGE", I assume the text and signature are both bundled in there.
Nope, RFC2440 divides everything in packets and as you didn't want/need packets I didn't know how to bundle them
Do you need a specific way to bundle them? If not I'll do (1byte header + r + s + message)

I guess I don't understand.  The point v1 non-clearsign is that you get a single block of opaque base64 that contains the original message and the signature, together.  The user should have no idea what's in it until they copy it into their wallet and it will spit out the message only if the signature is valid.  This is considered ideal since users have a tendency to only look for the message header and trust it without checking.  This way, they can't get the message unless they also check the signature.  

Does RFC2440 not mention how to encode and concatenate this data?  You can see what I'm talking about by just doing a regular "gpg --sign --armor file.txt".  Then when you "gpg -v file.txt.asc" it checks the signature, and writes out the signed data to a file.  I don't need the file operations, but I do want the bundling.  
RFC2440 says that you must communicate with blocks of packets, it describes all the types of packets you can create (signature, public key, private key, signer info, literal data, etc) and how to write them.
So yes it does mention how to bundle the sig+data, but as you said you didn't need OpenPGP compatibility I thought I didn't even have to stick to this 'packet rule'.

I'll try to be clearer:
  • Bitcoin's base64 is base64( leading byte + r + s )
  • My current code base64 (for v0, v1CS and v1B64) is base64( leading byte + r + s )
  • RFC2440 works with packets:
    • Verifying a clear text needs only a signature packet: base64( type + length + 04 + hash algorithm byte + pubkey type byte + timestamp + ... + MPI(r) + MPI(s) )
    • Verifying with included text needs a signature packet and a literal data packet: base64( type of literal data packet + len of literal data packet + flag + 00 + timestamp + message + type of pubkey packet + length of pubkey packet + 04 + hash algorithm byte + pubkey type byte + timestamp + ... + MPI(r) + MPI(s) )

As you can see, OpenPGP doesn't contain the leading byte so anyway I can't use strict RFC2440 to concatenate sig+data
A choice must be made because we can't use strict RFC2440 rules
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
I just released on github before your message: https://github.com/jackjack-jj/jasvet/blob/master/jasvet.py

Ok for 64-chars wide blocks and headers, I'll change that
Yes for the dashes, newlines, and key recovery matters

Fantastic.

Is the v1-Base64 you identified correctly?  It says "BEGIN SIGNATURE", but it should probably be "BEGINE BITCOIN MESSAGE", I assume the text and signature are both bundled in there.
Nope, RFC2440 divides everything in packets and as you didn't want/need packets I didn't know how to bundle them
Do you need a specific way to bundle them? If not I'll do (1byte header + r + s + message)

I guess I don't understand.  The point v1 non-clearsign is that you get a single block of opaque base64 that contains the original message and the signature, together.  The user should have no idea what's in it until they copy it into their wallet and it will spit out the message only if the signature is valid.  This is considered ideal since users have a tendency to only look for the message header and trust it without checking.  This way, they can't get the message unless they also check the signature.  

Does RFC2440 not mention how to encode and concatenate this data?  You can see what I'm talking about by just doing a regular "gpg --sign --armor file.txt".  Then when you "gpg -v file.txt.asc" it checks the signature, and writes out the signed data to a file.  I don't need the file operations, but I do want the bundling.  

I didn't say anything about your CPP additional matter. Was I unclear somewhere?

No, I was just clarifying.  There seemed to be some confusion earlier about where the key recovery should happen.  I was just clarifying that it needs to happen in the python code, but I'll give "extra credit" for the Crypto++ implementation.

Thanks!
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
Perhaps, also add a few comments there (or here), describing exactly how the v1 signing is done.  Basically, just mention which parts of RFC2440 were used, and how the signature is created exactly (i.e. I assume it matches the version-0 format, but it should be noted).
Ok!

And while you're at it, can you add a header to the file declaring that the code in this file is being released to the public domain? 
It was the point of CC0, but I'll explicit
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
I just released on github before your message: https://github.com/jackjack-jj/jasvet/blob/master/jasvet.py

Ok for 64-chars wide blocks and headers, I'll change that
Yes for the dashes, newlines, and key recovery matters

Is the v1-Base64 you identified correctly?  It says "BEGIN SIGNATURE", but it should probably be "BEGINE BITCOIN MESSAGE", I assume the text and signature are both bundled in there.
Nope, RFC2440 divides everything in packets and as you didn't want/need packets I didn't know how to bundle them
Do you need a specific way to bundle them? If not I'll do (1byte header + r + s + message)


I didn't say anything about your CPP additional matter. Was I unclear somewhere?



Edit: I deleted my previous post to answer yours
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
Ok, I assumed this was what you wanted
Released on github: https://github.com/jackjack-jj/jasvet/blob/master/jasvet.py

Great, I'll look at it when I get some time.  I won't get to it today, so if you want to tweak it any further, go ahead.  Perhaps, also add a few comments there (or here), describing exactly how the v1 signing is done.  Basically, just mention which parts of RFC2440 were used, and how the signature is created exactly (i.e. I assume it matches the version-0 format, but it should be noted).

And while you're at it, can you add a header to the file declaring that the code in this file is being released to the public domain? 

Thanks! 
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
This is looking good!   

A couple questions/comments.

--GPG keeps the armored blocks to 64-characters wide, not 80.
--Does this do proper dash-escaping? 
--Handles newlines properly?
--Signs the non-dash-escaped, windows-styled-newline string, or something like that (I don't remember the details, that was your job Smiley)
--Make it say "-----BEGIN BITCOIN SIGNED MESSAGE-----" and "-----BEGIN BITCOIN SIGNATURE-----"
--Is the v1-Base64 you identified correctly?  It says "BEGIN SIGNATURE", but it should probably be "BEGINE BITCOIN MESSAGE", I assume the text and signature are both bundled in there.

And these signatures use the key recovery?  I assume that's what the 1+64 bytes comment is. 

I really did want python signing.  But I was saying I would pay an extra 0.5 BTC to additionally implement key recovery in cppForSwig/EncryptionUtils.cpp using Crypto++, but it's not strictly necessary or part of the original bounty.
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
Ok then!
I think/hope that will anyway be useful in the future

For now I have that:
v0
Code:
{
 'message': 'jjj',
 'signature': 'G52Qg26N+v9BE7WlaG+MQUYF+35Or0UF6cWUp9bRVM46LFT8AP+spHCVLds9gpCh+IGcKLOCLYdLWKgFqvP82PY=', // =base64(signature)
 'address': '1BCwRkTsYzK5aNK4sdF7Bpti3PhrkPtLc4'
}

v1 Clear sig
Code:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

ldld
-----BEGIN PGP SIGNATURE-----
iHkEABMIACEFAlGOIpYCGwMGCwkIBwMCBhUIAgkKCwMWAgECHgECF4AACgkQQAqjLBlarMRT3wEA1IED    (OpenPGP packets)
GsDYPz4OTY0bn35RTz6RkyCh59i47DBnjih4S5IA/R3qcXG/V9Mx8uHzjaU1uM6CrS1II1aij+JqU6vR
2Gtp
=D1/a
-----END PGP SIGNATURE-----

v1 Base64
Code:
-----BEGIN SIGNATURE-----
kA0DAAgTU4HmRG72SLABywpiAFGOJKpsZGxkiHkEABMIACEFAlGOJKoCGwMGCwkIBwMCBhUIAgkKCwMW   (OpenPGP packets)
AgECHgECF4AACgkQU4HmRG72SLBCWAD8Db4nEv/poywtioVXy3nRCIwVkVJc8kULlRVpEeW4Os8BAJ2B
8qnmdGqEmyYbl3ZDV+Osp7440Cdl8WgSv3EHvAMf
=5wDl
-----END SIGNATURE-----



So instead of my clear sig, you'd want that, right?
Code:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

ldld
-----BEGIN PGP SIGNATURE-----
G52Qg26N+v9BE7WlaG+MQUYF+35Or0UF6cWUp9bRVM46LFT8AP+spHCVLds9gpCh+IGcKLOCLYdLWKgFqvP82PY= (same data than v0: 1+64 bytes, may be different if contains \n)
=crc24
-----END PGP SIGNATURE-----

But what about the base64 one? Just this?
Code:
-----BEGIN PGP SIGNATURE-----
G52Qg26N+v9BE7WlaG+MQUYF+35Or0UF6cWUp9bRVM46LFT8AP+spHCVLds9gpCh+IGcKLOCLYdLWKgFqvP82PY= (same data than v0: 1+64 bytes)
=crc24
-----END PGP SIGNATURE-----
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
Oh ok I misunderstood, I thought you wanted that for Python. I might look at that once the current problem is solved.

That problem is this one: I thought I was making mistakes in my implementation but looking at some codes I realized that there is currently not a single implementation of OpenPGP that accepts secp256k1.
I tried to add it in gnupg-ecc, but no luck yet...

So... I have done what you asked for (message signing with secp256k1 keys that follows RFC2440) but nobody can read those signatures yet.
This leads to two questions

  • 1. Is it enough to claim (a part of) the bounty? I'm not being greedy, it's just that I have other projects and I see that continuing this one (ie implementing OpenPGP verifying) will require some additional hours of work. In all cases, I'll finish and implement that verifying but the ETA's would be different.

  • 2. Say that I'm going to implement that now (bounty or not, it's more about the 'global' 'future' of secp256k1 signing with RFC2440). There's still a problem:
    • GPG needs to have the public key stored in your keyring to verify. AND that keyring doesn't accept secp256k1 keys.
    • GPG doesn't accept to verify signatures if the public key and the signature are in the same block. (Not a word about such behavior in RFCs though.)
    So, well... What should I do?
    • Create two blocks (key export + signature) ? (OK with GPG behavior BUT (1) two blocks to process: importing, then verifying, and (2) GPG doesn't support secp256k1 key import yet)
    • Stick to RFCs, break compatibility with GPG and create big signatures that contain the pubkey? (simpler to verify: only one block BUT will never work with GPG)



Anyway, I'll publish my signing code soon. This week hopefully. With both possibilities for problem 2.


PS: All this post is about Version 1 / OpenPGP signatures, not Version 0, which is done
legendary
Activity: 1428
Merit: 1093
Core Armory Developer

I do have the key recovery in my python code
Techwtf's implementation too

Okay, great. 

I mentioned expanding the Armory C++ utilities because it doesn't use OpenSSL.  It uses Crypto++.  I definitely want that code upgraded, and it might just be one night's worth of work to match the EC-math operations I already have, with the key-recovery algorithm.  Maybe a tad bit of Crypto++ doc searches looking for the needed operations.  That's worth 0.5 BTC to me.

For now, if the key recovery only works in python, that's fine.  It will fit into my interface.  I just wanted the key recovery as part of the C++ operations for other reasons.
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
Thanks scintill,

That's a nice compact implementation.  I like it.  I was just looking through the code...

@jackjack

I forgot that Bitcoin-Qt uses key recovery for the signatures.  Meaning, that you only need to provide the signature, and the public key can only be one of four different values.  Thus, signature and a couple extra bits.  This is something I don't have implemented in any of libraries yet, and it doesn't look trivial.   But the code is all there in the C++ from scintill, and I am considering putting it into my own "EncryptionUtils.h/.cpp".

I assume you're not going into the C++ code in Armory...?  Just making standalone python files?  That will work for now, though I can see that having the C++ key recovery would be useful.

If you want to take a shot at implementing it in EncryptionUtils.h/.cpp, I will throw in another 0.5 BTC (on success, of course!).  I already have EC math operations available in the library.  I'm pretty sure you can do most of it with what's already there.  Though, you might have to add a sqrt-function or something (I cheated with UncompressPoint, by just letting Crypto++ do the uncompression for me, so  I didn't actually implement it).
I do have the key recovery in my python code
Techwtf's implementation too
full member
Activity: 140
Merit: 100
Here is a working bitcoin-qt compatible signer & checker in python, with ECDSA code embedded, it even supports compressed pubkeys.
https://gist.github.com/anonymous/da91bd30fa068ae4a3bb

if I'm qualified to get a proportion of the bounty: 1HFhtvzNEiy9eooLSJRMyZ1XB2FXgYGvCH. I'm still happy even not anyway.

the sign example is taken from brainwallet.org.
missing code:
Code:
import struct
def encode32(i):
  return struct.pack('
def encode64(i):
  return struct.pack('
full member
Activity: 140
Merit: 100
Here is a working bitcoin-qt compatible signer & checker in python, with ECDSA code embedded, it even supports compressed pubkeys.
https://gist.github.com/anonymous/da91bd30fa068ae4a3bb

if I'm qualified to get a proportion of the bounty: 1HFhtvzNEiy9eooLSJRMyZ1XB2FXgYGvCH. I'm still happy even not anyway.

the sign example is taken from brainwallet.org.
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
Thanks scintill,

That's a nice compact implementation.  I like it.  I was just looking through the code...

@jackjack

I forgot that Bitcoin-Qt uses key recovery for the signatures.  Meaning, that you only need to provide the signature, and the public key can only be one of four different values.  Thus, signature and a couple extra bits.  This is something I don't have implemented in any of libraries yet, and it doesn't look trivial.   But the code is all there in the C++ from scintill, and I am considering putting it into my own "EncryptionUtils.h/.cpp".

I assume you're not going into the C++ code in Armory...?  Just making standalone python files?  That will work for now, though I can see that having the C++ key recovery would be useful.

If you want to take a shot at implementing it in EncryptionUtils.h/.cpp, I will throw in another 0.5 BTC (on success, of course!).  I already have EC math operations available in the library.  I'm pretty sure you can do most of it with what's already there.  Though, you might have to add a sqrt-function or something (I cheated with UncompressPoint, by just letting Crypto++ do the uncompression for me, so  I didn't actually implement it).
sr. member
Activity: 448
Merit: 254
The 1 btc additional bounty has been claimed by scintill.  He has provided a patch to the official bitcoin repo that includes a separate verifysig program.

I've rebuilt it outside of the bitcoin repo (copying over stuff it depends on) and put it on github: https://github.com/scintill/bitcoin-signature-tools .  It's a C++ command-line verifier for the bitcoin-qt bare signatures.

It's easier to build than what I gave slothbag originally and won't break if they shuffle files around in the bitcoin repo.  I've just noticed that I somehow missed the fact that slothbag asked for signing, too, and this is only verifying right now.  He paid the bounty so I guess he's happy with it Grin, but since those were the original terms he can still require me to add signing for free if he'd like.  Others can request it too, but I don't have time to make it a priority unless there's a bounty.
sr. member
Activity: 369
Merit: 250
The 1 btc additional bounty has been claimed by scintill.  He has provided a patch to the official bitcoin repo that includes a separate verifysig program.

Cheers
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
Can I add to the bounty.. I need a small standalone C/C++ program written to do the same message signing/verification. I dont need the version 1 proposal, just version 0 which is compatible with bitcoin-qt.

You can copy the code from bitcoin-qt or use something like libccoin, i'm not fussed.  Just as long as its small and fast.

I can add another 1 btc for it Smiley

Sure.  I assume jackjack will be making some python blackboxes, one for each version.  I saw your other thread about this, and it does sound like a good match.  You can easily invoke the python directly.  Alternatively, I have all the ECDSA operations wrapped up nicely in the C++ code which is wrapped up in the python.  You could actually access the C++ code directly in a main.cpp file, but you do need a little bit extra to get it working.  Just a thought...

sr. member
Activity: 369
Merit: 250
Can I add to the bounty.. I need a small standalone C/C++ program written to do the same message signing/verification. I dont need the version 1 proposal, just version 0 which is compatible with bitcoin-qt.

You can copy the code from bitcoin-qt or use something like libccoin, i'm not fussed.  Just as long as its small and fast.

I can add another 1 btc for it Smiley
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
OK, I'm up for that
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
Great, I thought your deadline would have been shorter. I'm ok to look at it if you're ok.
I just want to be sure I understand: you want to sign a message with a private key? I thought Armory already signed messages

Armory's signmessage is not compatible with Bitcoin-Qt.  Their signatures cannot be cross-verified (not even the same format).  I didn't want to follow Bitcoin-Qt because I hate bare signatures.  So I proposed I would become compatible if they started to support "proper" signatures:  which is the original, properly encoded text, along with the signature.  I didn't even get any commitment from them on this but someone suggested that RFC2440 was the way to go, and if I lead, I might get them to follow.  Especially if it builds off an existing standard.

"Version 0" will be compatible with the existing Bitcoin-Qt, so that bare-signatures will cross-verify.  I know some people still want the backwards compatibility. 

"Version 1" implements the target behavior:  copy this base64 block of text into and it pops up a windows saying "The following message has a verified signature from Address X:  ".  This is how message signing should be.  Not multiple copy&paste ops which fail if you miss a whitespace character.
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
Great, I thought your deadline would have been shorter. I'm ok to look at it if you're ok.
I just want to be sure I understand: you want to sign a message with a private key? I thought Armory already signed messages
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
I'm interested. In how much time this needs to be done?

I'd like to have it done in a couple weeks.  But if there are snags and it can't be done before then, I guess there's not much I can do, eh?  But if you look at the RFC, it doesn't look like it will be terribly difficult.  Especially in python.
legendary
Activity: 1176
Merit: 1280
May Bitcoin be touched by his Noodly Appendage
I'm interested. In how much time this needs to be done?
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
Raised the bounty to 2 BTC!
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
    Claimed by jackjack!

    Original message:



    I was going to do this myself, but it should be fairly straightforward to implement and I have some other priorities right now.  But there has been demand for it, so I'll let someone else take a shot it for me.  The string manipulations should be trivial in python.

    Goals:
    • (1) Create a new message signing algorithm that I can easily wrap with a nice GUI
    • (2) It should have three modes:
    •  
      • (a) Bare signatures, compatible with signatures from Bitcoin-Qt/bitcoind
      • (b) RFC2440-compatible, ASCII-armored signature blocks (Base64), with the CRC-24
      • (c) RFC2440-compatible, ASCII-armored signature blocks (Clearsign)
    • (3) It would be neat if the clear-signed messages were somehow compatible with bare signatures: i.e. you could copy the text into Bitcoin-Qt and signature into Bitcoin-Qt and it would verify properly.  But I highly doubt that's possible... maybe for simple messages
    • (4) Unit-tests that demonstrate dash-escaping, newline behavior, and unicode support
    • (5) Be willing to release the copyright of your solution to public domain
      The reason I think (3) is not possible is that
    Sections 6 and 7 of RFC2440 indicate changing newlines (\n) to Windows newlines (\r\n).  And dash-escaping the clear-signed text, but using the original text for signing.  I haven't looked too deeply into it, but what I've seen is that it won't be too complicated, just requires some attention to detail.  Such as getting CRC-24 coded correctly (also looks simple).  

    For Base64 encoding: go figure, python has it built-in:  "import base64;  base64.b64encode(msg), and base64.b64decode(sigBlock)"

    This doesn't need to be integrated into the GUI at all.  Just have it operate on raw strings, and I will integrate it into the GUI.  The GUI would probably have radio buttons that say "Version 0 (Bare Signature/Bitcoin-Qt)", "Version 1 (Base64)", "Version 1 (Clearsign)", and the appropriate signature would be produced for the text that is in the text box (which may include newlines, dashes, and unicode).

    Anyone up for the task?  [/list][/list]
    Jump to: