Support
Quality
Security
License
Reuse
kandi has reviewed coldcore and discovered the below as its top functions. This is intended to give you an instant insight into coldcore implemented functionality, and help decide if they suit your requirements.
Zero install process for most platforms
Designed for simplicity and auditability
No GUI, terminal only (curses and command-line)
Works in terms of script descriptors and PSBTs
Minimal dependencies: Bitcoin Core, Python 3 interpreter, nothing else
Supports only airgapped, opensource hardware wallets
Integrates with GPG and pass for secure xpub storage
Design
Status
Usage
Security assumptions
Configuration
FAQ Why is there no GUI? Why do you only support Coldcard? Will you add others? Why did you use Python and not {Rust,Haskell,C++}? Why do you encrypt the config file by default with GPG?
Donate
TODO/Roadmap
Auditing
.
├── bin
│ ├── compile # generates final `coldcore` script
│ └── sign_release
├── coldcore
├── sigs # signatures for verification
│ └── coldcore-0.1.0-alpha.asc
└── src
├── coldcore
│ ├── crypto.py # a few basic cryptographic utilities
│ ├── __init__.py
│ ├── main.py # most logic is here; wallet ops, CLI, models
│ ├── test_coldcard.py
│ ├── test_crypto.py
│ ├── thirdparty
│ │ ├── bitcoin_rpc.py # taken from python-bitcoinlib
│ │ ├── clii.py # taken from jamesob/clii
│ │ ├── __init__.py
│ │ └── py.typed
│ └── ui.py # presentation logic, curses
├── requirements-dev.txt
└── setup.py # for development use only
Receiving
% ./coldcore newaddr --help
usage: coldcore newaddr [-h] [--num NUM]
optional arguments:
-h, --help show this help message and exit
--num NUM default: 1
Sending
% SEND_TO_ADDR=tb1qj2sjxuhxqyfgxkf6kqnthskqtum8hr2zr0l95j
% ./coldcore prepare-send $SEND_TO_ADDR 0.00001
-- 1 inputs, 2 outputs
-- fee: 0.00000141 BTC (14.10% of amount)
✔ wrote PSBT to unsigned-20201222-0920.psbt - sign with coldcard
% # I transfer the .psbt file to a microSD, sign with the coldcard, and plug
% # the microSD back in...
% ./coldcore broadcast /media/james/3264-6339/unsigned-20201222-0920-signed.psbt
! About to send a transaction:
<- tb1qumfrma8gy08wcfq0ugwknh8cy0cdds5df8lfya (0.00009859 BTC)
-> tb1qj2sjxuhxqyfgxkf6kqnthskqtum8hr2zr0l95j (0.00001000 BTC) (your address)
-> tb1qfs2yd54mmdzvrsnzdqk852crzclkn8cfx8cgzf (0.00008718 BTC) (your address)
? look okay? [y/N]: y
✔ tx sent: d859cfe7a05e70e5d1e734244fb731c988bb29b236bd108529145cf987b8467f
d859cfe7a05e70e5d1e734244fb731c988bb29b236bd108529145cf987b8467f
Comparison to other wallets
github.com/AlDanial/cloc v 1.86 T=0.04 s (27.3 files/s, 84781.1 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
Python 1 673 313 2123
-------------------------------------------------------------------------------
Donate
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
bc1qgyq7lxmk359c3vyxzz674pr8a9gnguxkgdw55p
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCgAdFiEEGNRVI1NPYuZCSIrGepNdrbLETwUFAl/gLmsACgkQepNdrbLE
TwX8vg/+OZkL1+RbBjV8KNkqp7rQY/O1XXEOYX8JSYM+GEwmeACSGSbV6d7OqmTx
oofjmu5CJ93a2QpE8qPMIr2knRbUrfouAVzPqiF3RNp+UdEqdoLJkAox9MhXm9aG
d/PGYYx3Vf0Lq0bo6eUc19XU0bc38RRV0cjAwpKvfyc0u6SW/t6K6zjrXhZhcuga
LT6DqUxDXD5xDLpjeICDQgazraOr7QG8r39Yw5WSC95ewysiFOp/JQ5Zik6ut9LS
rXEX6+SqwQZOm0xcynqrYjFuiCdHGU39Eiy0DBXOTjeWQyBAq9pTRMXLId2dqyy1
iAbot2YmtNHuRH519YAakh4C0r2oFN7B2qQ2twIvt/rWtkmv3FWvcdKw6H0Q+4oc
VaD9S8cMVoR+bJEtY3EjLkUyd0zmxLuIgKSpdzchru07O/DhvvLvsNwgmzJMoD9f
iH3RfqMEJY+iAQFfoCA/sPwz56xWMW33Ta57+xfNSCTOtOLIJ5c0eqoCHoQ0PlAb
kJIEZ/S7qbbF1DGSlMG/Zbw8OHP0dBuKYjIev0CpFplQAV4SIzzOpxmVMQpahZjH
1RdH9J75+N2l4QgAWR0cJSxW0E56r3J94lM6fgieWySDsxteoAMXqWgLMEpMXNfA
Ze9i1ZlGxIIes25pRiyXXmwys3u1u8VOMmfiLe9VzStIJOMerIo=
=Q7Sw
-----END PGP SIGNATURE-----
QUESTION
ECSDA sign with Python, verify with JS
Asked 2022-Apr-10 at 18:16I'm trying to achieve the exact opposite of this here where I need to sign a payload in Python using ECDSA and be able to verify the signature in JS.
Here is my attempt, but I'm pretty sure I'm missing something with data transformation on either or both ends.
(Key types are the same as in the answer provided to the question above)
I've tried some other variations but nothing worked so far.
(The verification on JS returns False)
Python:
import os
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric.utils import (
encode_dss_signature,
decode_dss_signature
)
from cryptography.hazmat.primitives.serialization import load_der_public_key, load_pem_private_key, load_der_private_key
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives import hashes
from cryptography.exceptions import InvalidSignature
import base64
import json
from hashlib import sha256
def order_dict(dictionary):
return {k: order_dict(v) if isinstance(v, dict) else v
for k, v in sorted(dictionary.items())}
async def sign_payload(private_key, data):
"""
Generate a signature based on the data using the local private key.
"""
data = order_dict(data)
# Separators prevent adding whitespaces around commas and :
payload = json.dumps(data, separators=(',', ':')).encode('utf-8')
# payload = base64.b64decode(json.dumps(data, separators=(',', ':')))
sig = private_key.sign(
payload,
ec.ECDSA(hashes.SHA256())
)
return sig
JS:
export function b642ab(base64_string){
return Uint8Array.from(window.atob(base64_string), c => c.charCodeAt(0));
}
export async function verifySignature(signature, public_key, data_in) {
// Sorting alphabetically to avoid signature mismatch with BE
const sorted_data_in = sortObjKeysAlphabetically(data_in);
var dataStr = JSON.stringify(sorted_data_in)
console.log(dataStr)
var dataBuf = new TextEncoder().encode(dataStr)
return window.crypto.subtle.verify(
{
name: "ECDSA",
namedCurve: "P-256",
hash: { name: "SHA-256" },
},
public_key,
b642ab(utf8.decode(signature)),
dataBuf
);
}
await sign_payload(private_dsa_key, generated_payload)
ANSWER
Answered 2022-Apr-10 at 18:16The main problem is that both codes use different signature formats:
sign_payload()
in the Python code generates an ECDSA signature in ASN.1/DER format. The WebCrypto API on the other hand can only handle the IEEE P1363 format.
Since the Python Cryptography library is much more convenient than the low level WebCrypto API it makes sense to do the conversion in Python code.
The following Python code is based on your code, but additionally performs the transformation into the IEEE P1363 format at the end:
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from cryptography.hazmat.primitives import hashes
import base64
import json
#def order_dict(dictionary):
# return {k: order_dict(v) if isinstance(v, dict) else v
# for k, v in sorted(dictionary.items())}
def sign_payload(private_key, data):
"""
Generate a signature based on the data using the local private key.
"""
#order_dict(data) # not considered!
# Separators prevent adding whitespaces around commas and :
payload = json.dumps(data, separators=(',', ':')).encode('utf-8')
print(payload.decode('utf-8'))
sig = private_key.sign(
payload,
ec.ECDSA(hashes.SHA256())
)
return sig
privateKeyPem = b'''-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgrW9XiIs4/Kb0q8kl
TmF3oIwSn4NO3xAjs08F0lJ/5UOhRANCAAQykdP4c0ozvOOHHSNkMfLNCWRstXTG
TQf9MWjqB9PbeKyHnxuU82FisUjnVD9zO+QDAK0tnP/qzWf8zxoD0vVW
-----END PRIVATE KEY-----'''
privateKey = load_pem_private_key(privateKeyPem, password=None, backend=default_backend())
data = {"key1": "value1", "key2": "value2"}
signatureDER = sign_payload(privateKey, data)
# Convert signature format
(r, s) = decode_dss_signature(signatureDER)
signatureP1363 = r.to_bytes(32, byteorder='big') + s.to_bytes(32, byteorder='big')
print(base64.b64encode(signatureP1363).decode('utf-8'))
A possible output is:
{"key1":"value1","key2":"value2"}
KIkBK4pxSFq/UdsPb/mYCC3y7iAJlULC/jizNp9DrvFFIvZaUjx/M0SAQC7CeBIlLmKzfkGx1fOr7OJ8VlwAdg==
Note that for this test, the order_dict(data)
call is commented out, since the JavaScript counterpart was not posted.
In the JavaScript code, remove the utf8.decode()
when Base64 decoding the signature. Apart from that the code is OK. The following JavaScript code is based on your code, with the addition of the key import:
(async () => {
var x509pem = `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMpHT+HNKM7zjhx0jZDHyzQlkbLV0
xk0H/TFo6gfT23ish58blPNhYrFI51Q/czvkAwCtLZz/6s1n/M8aA9L1Vg==
-----END PUBLIC KEY-----`
var public_key = await importPublicKey(x509pem)
var data_in = {
key1: "value1",
key2: "value2"
}
var signature = "KIkBK4pxSFq/UdsPb/mYCC3y7iAJlULC/jizNp9DrvFFIvZaUjx/M0SAQC7CeBIlLmKzfkGx1fOr7OJ8VlwAdg=="
var verified = await verifySignature(signature, public_key, data_in)
console.log(verified);
})();
function b642ab(base64_string){
return Uint8Array.from(window.atob(base64_string), c => c.charCodeAt(0));
}
async function verifySignature(signature, public_key, data_in) {
// Sorting alphabetically to avoid signature mismatch with BE
//const sorted_data_in = sortObjKeysAlphabetically(data_in);
//var dataStr = JSON.stringify(sorted_data_in)
var dataStr = JSON.stringify(data_in)
console.log(dataStr)
var dataBuf = new TextEncoder().encode(dataStr)
return window.crypto.subtle.verify(
{
name: "ECDSA",
namedCurve: "P-256",
hash: { name: "SHA-256" },
},
public_key,
b642ab(signature),
dataBuf
);
}
async function importPublicKey(spkiPem) {
return await window.crypto.subtle.importKey(
"spki",
getSpkiDer(spkiPem),
{name: "ECDSA", namedCurve: "P-256"},
false,
["verify"]
);
}
function getSpkiDer(spkiPem){
const pemHeader = "-----BEGIN PUBLIC KEY-----";
const pemFooter = "-----END PUBLIC KEY-----";
var pemContents = spkiPem.substring(pemHeader.length, spkiPem.length - pemFooter.length);
var binaryDerString = window.atob(pemContents);
return str2ab(binaryDerString);
}
function str2ab(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
The message can be successfully verified with the JavaScript code using the signature generated by the Python code.
Note that - analogous to the Python code - sortObjKeysAlphabetically()
has been commented out because of the missing implementation.
Community Discussions, Code Snippets contain sources that include Stack Exchange Network
No vulnerabilities reported
Save this library and start creating your kit
Explore Related Topics
Save this library and start creating your kit