def encrypt(privkey, passphrase): """ BIP0038 non-ec-multiply encryption. Returns BIP0038 encrypted privkey. :param privkey: Private key :type privkey: Base58 :param str passphrase: UTF-8 encoded passphrase for encryption :return: BIP0038 non-ec-multiply encrypted wif key :rtype: Base58 """ privkeyhex = repr(privkey) # hex addr = format(privkey.uncompressed.address, "BTC") a = compat_bytes(addr, 'ascii') salt = hashlib.sha256(hashlib.sha256(a).digest()).digest()[0:4] if SCRYPT_MODULE == "scrypt": if sys.version >= '3.0.0': key = scrypt.hash(passphrase, salt, 16384, 8, 8) else: key = scrypt.hash(str(passphrase), str(salt), 16384, 8, 8) elif SCRYPT_MODULE == "pylibscrypt": key = scrypt.scrypt(compat_bytes(passphrase, "utf-8"), salt, 16384, 8, 8) else: raise ValueError("No scrypt module loaded") (derived_half1, derived_half2) = (key[:32], key[32:]) aes = AES.new(derived_half2) encrypted_half1 = _encrypt_xor(privkeyhex[:32], derived_half1[:16], aes) encrypted_half2 = _encrypt_xor(privkeyhex[32:], derived_half1[16:], aes) " flag byte is forced 0xc0 because Graphene only uses compressed keys " payload = (b'\x01' + b'\x42' + b'\xc0' + salt + encrypted_half1 + encrypted_half2) " Checksum " checksum = hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4] privatekey = hexlify(payload + checksum).decode('ascii') return Base58(privatekey)
def __bytes__(self): if not self.data: return compat_bytes(Bool(0)) else: return compat_bytes(Bool(1)) + compat_bytes( self.data) if compat_bytes(self.data) else compat_bytes( Bool(0))
def varint(n): """ Varint encoding """ data = b'' while n >= 0x80: data += compat_bytes([(n & 0x7f) | 0x80]) n >>= 7 data += compat_bytes([n]) return data
def __bytes__(self): if self.data is None: return bytes() b = b"" for name, value in self.data.items(): if isinstance(value, str): b += compat_bytes(value, 'utf-8') else: b += compat_bytes(value) return b
def compressed(self): """ Derive compressed public key """ order = ecdsa.SECP256k1.generator.order() p = ecdsa.VerifyingKey.from_string( compat_bytes(self), curve=ecdsa.SECP256k1).pubkey.point x_str = ecdsa.util.number_to_string(p.x(), order) # y_str = ecdsa.util.number_to_string(p.y(), order) compressed = hexlify( compat_bytes(compat_chr(2 + (p.y() & 1)), 'ascii') + x_str).decode('ascii') return (compressed)
def verify(self, pubkeys=[], chain=None): if not chain: raise ValueError("Chain needs to be provided!") chain_params = self.getChainParams(chain) self.deriveDigest(chain) signatures = self.data["signatures"].data pubKeysFound = [] for signature in signatures: sig = compat_bytes(signature)[1:] if sys.version >= '3.0': recoverParameter = (compat_bytes(signature)[0]) - 4 - 27 # recover parameter only else: recoverParameter = ord((compat_bytes(signature)[0])) - 4 - 27 if USE_SECP256K1: ALL_FLAGS = secp256k1.lib.SECP256K1_CONTEXT_VERIFY | \ secp256k1.lib.SECP256K1_CONTEXT_SIGN # Placeholder pub = secp256k1.PublicKey(flags=ALL_FLAGS) # Recover raw signature sig = pub.ecdsa_recoverable_deserialize(sig, recoverParameter) # Recover PublicKey verifyPub = secp256k1.PublicKey( pub.ecdsa_recover(compat_bytes(self.message), sig)) # Convert recoverable sig to normal sig normalSig = verifyPub.ecdsa_recoverable_convert(sig) # Verify verifyPub.ecdsa_verify(compat_bytes(self.message), normalSig) phex = hexlify( verifyPub.serialize(compressed=True)).decode('ascii') pubKeysFound.append(phex) else: p = self.recover_public_key(self.digest, sig, recoverParameter) # Will throw an exception of not valid p.verify_digest( sig, self.digest, sigdecode=ecdsa.util.sigdecode_string) phex = hexlify(self.compressedPubkey(p)).decode('ascii') pubKeysFound.append(phex) for pubkey in pubkeys: if not isinstance(pubkey, PublicKey): raise Exception("Pubkeys must be array of 'PublicKey'") k = pubkey.unCompressed()[2:] if k not in pubKeysFound and repr(pubkey) not in pubKeysFound: k = PublicKey(PublicKey(k).compressed()) f = format(k, chain_params["prefix"]) raise Exception("Signature for %s missing!" % f) return pubKeysFound
def decrypt(encrypted_privkey, passphrase): """BIP0038 non-ec-multiply decryption. Returns WIF privkey. :param Base58 encrypted_privkey: Private key :param str passphrase: UTF-8 encoded passphrase for decryption :return: BIP0038 non-ec-multiply decrypted key :rtype: Base58 :raises SaltException: if checksum verification failed (e.g. wrong password) """ d = unhexlify(base58decode(encrypted_privkey)) d = d[2:] # remove trailing 0x01 and 0x42 flagbyte = d[0:1] # get flag byte d = d[1:] # get payload assert flagbyte == b'\xc0', "Flagbyte has to be 0xc0" salt = d[0:4] d = d[4:-4] if SCRYPT_MODULE == "scrypt": if sys.version >= '3.0.0': key = scrypt.hash(passphrase, salt, 16384, 8, 8) else: key = scrypt.hash(str(passphrase), str(salt), 16384, 8, 8) elif SCRYPT_MODULE == "pylibscrypt": key = scrypt.scrypt(compat_bytes(passphrase, "utf-8"), salt, 16384, 8, 8) else: raise ValueError("No scrypt module loaded") derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] encryptedhalf1 = d[0:16] encryptedhalf2 = d[16:32] aes = AES.new(derivedhalf2) decryptedhalf2 = aes.decrypt(encryptedhalf2) decryptedhalf1 = aes.decrypt(encryptedhalf1) privraw = decryptedhalf1 + decryptedhalf2 privraw = ('%064x' % (int(hexlify(privraw), 16) ^ int(hexlify(derivedhalf1), 16))) wif = Base58(privraw) """ Verify Salt """ privkey = PrivateKey(format(wif, "wif")) addr = format(privkey.uncompressed.address, "BTC") a = compat_bytes(addr, 'ascii') saltverify = hashlib.sha256(hashlib.sha256(a).digest()).digest()[0:4] if saltverify != salt: raise SaltException( 'checksum verification failed! Password may be incorrect.') return wif
def get_private(self): """ Derive private key from the brain key and the current sequence number """ a = compat_bytes(self.account + self.role + self.password, 'utf8') s = hashlib.sha256(a).digest() return PrivateKey(hexlify(s).decode('ascii'))
def get_private(self): """ Derive private key from the brain key and the current sequence number """ encoded = "%s %d" % (self.brainkey, self.sequence) a = compat_bytes(encoded, 'ascii') s = hashlib.sha256(hashlib.sha512(a).digest()).digest() return PrivateKey(hexlify(s).decode('ascii'))
def base58encode(hexstring): byteseq = compat_bytes(hexstring, 'ascii') byteseq = unhexlify(byteseq) byteseq = compat_bytes(byteseq) n = 0 leading_zeroes_count = 0 for c in byteseq: n = n * 256 + c if n == 0: leading_zeroes_count += 1 res = bytearray() while n >= 58: div, mod = divmod(n, 58) res.insert(0, BASE58_ALPHABET[mod]) n = div else: res.insert(0, BASE58_ALPHABET[n]) return (BASE58_ALPHABET[0:1] * leading_zeroes_count + res).decode('ascii')
def encode_memo(priv, pub, nonce, message, **kwargs): """ Encode a message with a shared secret between Alice and Bob :param PrivateKey priv: Private Key (of Alice) :param PublicKey pub: Public Key (of Bob) :param int nonce: Random nonce :param str message: Memo message :return: Encrypted message :rtype: hex """ from smokebase import transactions shared_secret = get_shared_secret(priv, pub) aes, check = init_aes(shared_secret, nonce) raw = compat_bytes(message, 'utf8') " Padding " BS = 16 if len(raw) % BS: raw = _pad(raw, BS) " Encryption " cipher = hexlify(aes.encrypt(raw)).decode('ascii') prefix = kwargs.pop("prefix", default_prefix) s = OrderedDict([ ("from", format(priv.pubkey, prefix)), ("to", format(pub, prefix)), ("nonce", nonce), ("check", check), ("encrypted", cipher), ("from_priv", repr(priv)), ("to_pub", repr(pub)), ("shared_secret", shared_secret), ]) tx = Memo(**s) return "#" + base58encode(hexlify(compat_bytes(tx)).decode("ascii"))
def deriveDigest(self, chain): chain_params = self.getChainParams(chain) # Chain ID self.chainid = chain_params["chain_id"] # Do not serialize signatures sigs = self.data["signatures"] self.data["signatures"] = [] # Get message to sign # bytes(self) will give the wire formatted data according to # GrapheneObject and the data given in __init__() self.message = unhexlify(self.chainid) + compat_bytes(self) self.digest = hashlib.sha256(self.message).digest() # restore signatures self.data["signatures"] = sigs
def decode_memo(priv, message): """ Decode a message with a shared secret between Alice and Bob :param PrivateKey priv: Private Key (of Bob) :param base58encoded message: Encrypted Memo message :return: Decrypted message :rtype: str :raise ValueError: if message cannot be decoded as valid UTF-8 string """ " decode structure " raw = base58decode(message[1:]) from_key = PublicKey(raw[:66]) raw = raw[66:] to_key = PublicKey(raw[:66]) raw = raw[66:] nonce = str(struct.unpack_from("<Q", unhexlify(raw[:16]))[0]) raw = raw[16:] check = struct.unpack_from("<I", unhexlify(raw[:8]))[0] raw = raw[8:] cipher = raw if repr(to_key) == repr(priv.pubkey): shared_secret = get_shared_secret(priv, from_key) elif repr(from_key) == repr(priv.pubkey): shared_secret = get_shared_secret(priv, to_key) else: raise ValueError("Incorrect PrivateKey") " Init encryption " aes, checksum = init_aes(shared_secret, nonce) " Check " assert check == checksum, "Checksum failure" " Encryption " # remove the varint prefix (FIXME, long messages!) message = cipher[2:] message = aes.decrypt(unhexlify(compat_bytes(message, 'ascii'))) try: return _unpad(message.decode('utf8'), 16) except: # noqa FIXME(sneak) raise ValueError(message)
def unicodify(self): r = [] for s in self.data: o = ord(s) if o <= 7: r.append("u%04x" % o) elif o == 8: r.append("b") elif o == 9: r.append("\t") elif o == 10: r.append("\n") elif o == 11: r.append("u%04x" % o) elif o == 12: r.append("f") elif o == 13: r.append("\r") elif 13 < o < 32: r.append("u%04x" % o) else: r.append(s) return compat_bytes("".join(r), "utf-8")
def __bytes__(self): """ Returns the raw private key """ return compat_bytes(self._wif)
def __bytes__(self): """ Returns the raw public key (has length 33)""" return compat_bytes(self._pk)
def __bytes__(self): return compat_bytes(Id(self.opId)) + compat_bytes(self.op)
def __bytes__(self): return compat_bytes(self.length) + b"".join( [compat_bytes(a) for a in self.data])
def _unpad(s, BS): count = int(struct.unpack('B', compat_bytes(s[-1], 'ascii'))[0]) if compat_bytes(s[-count::], 'ascii') == count * struct.pack('B', count): return s[:-count] return s
def sign(self, wifkeys, chain=None): """ Sign the transaction with the provided private keys. :param list wifkeys: Array of wif keys :param str chain: identifier for the chain """ if not chain: raise ValueError("Chain needs to be provided!") self.deriveDigest(chain) # Get Unique private keys self.privkeys = [] [ self.privkeys.append(item) for item in wifkeys if item not in self.privkeys ] # Sign the message with every private key given! sigs = [] for wif in self.privkeys: p = compat_bytes(PrivateKey(wif)) i = 0 if USE_SECP256K1: ndata = secp256k1.ffi.new("const int *ndata") ndata[0] = 0 while True: ndata[0] += 1 privkey = secp256k1.PrivateKey(p, raw=True) sig = secp256k1.ffi.new( 'secp256k1_ecdsa_recoverable_signature *') signed = secp256k1.lib.secp256k1_ecdsa_sign_recoverable( privkey.ctx, sig, self.digest, privkey.private_key, secp256k1.ffi.NULL, ndata) assert signed == 1 signature, i = privkey.ecdsa_recoverable_serialize(sig) if self._is_canonical(signature): i += 4 # compressed i += 27 # compact break else: cnt = 0 sk = ecdsa.SigningKey.from_string(p, curve=ecdsa.SECP256k1) while 1: cnt += 1 if not cnt % 20: log.info("Still searching for a canonical signature. " "Tried %d times already!" % cnt) # Deterministic k k = ecdsa.rfc6979.generate_k( sk.curve.generator.order(), sk.privkey.secret_multiplier, hashlib.sha256, hashlib.sha256( self.digest + struct.pack("d", time.time( )) # use the local time to randomize the signature ).digest()) # Sign message # sigder = sk.sign_digest( self.digest, sigencode=ecdsa.util.sigencode_der, k=k) # Reformating of signature # r, s = ecdsa.util.sigdecode_der(sigder, sk.curve.generator.order()) signature = ecdsa.util.sigencode_string( r, s, sk.curve.generator.order()) # This line allows us to convert a 2.7 byte array(which is just binary) to an array of byte values. # We can then use the elements in sigder as integers, as in the following two lines. sigder = array.array('B', sigder) # Make sure signature is canonical! # lenR = sigder[3] lenS = sigder[5 + lenR] if lenR is 32 and lenS is 32: # Derive the recovery parameter # i = self.recoverPubkeyParameter( self.digest, signature, sk.get_verifying_key()) i += 4 # compressed i += 27 # compact break # pack signature # sigstr = struct.pack("<B", i) sigstr += signature sigs.append(Signature(sigstr)) self.data["signatures"] = Array(sigs) return self
def __bytes__(self): # FIXME constraint data to self.length d = unhexlify(compat_bytes(self.data, 'utf-8')) return varint(len(d)) + d
def __bytes__(self): return varint(self.type_id) + compat_bytes(self.data)
def __bytes__(self): return compat_bytes(self.data)
def compressedPubkey(self, pk): order = pk.curve.generator.order() p = pk.pubkey.point x_str = ecdsa.util.number_to_string(p.x(), order) return compat_bytes(compat_chr(2 + (p.y() & 1)), 'ascii') + x_str
def isempty(self): if not self.data: return True return not bool(compat_bytes(self.data))
def deriveChecksum(self, s): """ Derive the checksum """ checksum = hashlib.sha256(compat_bytes(s, "ascii")).hexdigest() return checksum[:4]
def __bytes__(self): b = b"" b += varint(len(self.data)) for e in self.data: b += compat_bytes(e[0]) + compat_bytes(e[1]) return b
def __bytes__(self): """ Returns the raw content of the ``Base58CheckEncoded`` address """ if self._address is None: return compat_bytes(self.derivesha512address()) else: return compat_bytes(self._address)
def __bytes__(self): return compat_bytes(self.instance) # only yield instance
def __bytes__(self): # padding asset = self.asset + "\x00" * (7 - len(self.asset)) amount = round(float(self.amount) * 10**self.precision) return (struct.pack("<q", amount) + struct.pack("<b", self.precision) + compat_bytes(asset, "ascii"))