Signer/Encrypted: use custom Base58Check prefixes
This commit is contained in:
parent
dee9c470fd
commit
e92e1aee17
@ -320,6 +320,11 @@ module Prefix = struct
|
|||||||
let secp256k1_secret_key = "\017\162\224\201" (* spsk(54) *)
|
let secp256k1_secret_key = "\017\162\224\201" (* spsk(54) *)
|
||||||
let p256_secret_key = "\016\081\238\189" (* p2sk(54) *)
|
let p256_secret_key = "\016\081\238\189" (* p2sk(54) *)
|
||||||
|
|
||||||
|
(* 56 *)
|
||||||
|
let ed25519_encrypted_seed = "\007\090\060\179\041" (* edesk(88) *)
|
||||||
|
let secp256k1_encrypted_secret_key = "\009\237\241\174\150" (* spesk(88) *)
|
||||||
|
let p256_encrypted_secret_key = "\009\048\057\115\171" (* p2esk(88) *)
|
||||||
|
|
||||||
(* 33 *)
|
(* 33 *)
|
||||||
let secp256k1_public_key = "\003\254\226\086" (* sppk(55) *)
|
let secp256k1_public_key = "\003\254\226\086" (* sppk(55) *)
|
||||||
let p256_public_key = "\003\178\139\127" (* p2pk(55) *)
|
let p256_public_key = "\003\178\139\127" (* p2pk(55) *)
|
||||||
|
@ -31,6 +31,10 @@ module Prefix : sig
|
|||||||
val p256_public_key: string
|
val p256_public_key: string
|
||||||
val p256_secret_key: string
|
val p256_secret_key: string
|
||||||
val p256_signature: string
|
val p256_signature: string
|
||||||
|
val ed25519_encrypted_seed: string
|
||||||
|
val secp256k1_encrypted_secret_key: string
|
||||||
|
val p256_encrypted_secret_key: string
|
||||||
|
|
||||||
val generic_signature: string
|
val generic_signature: string
|
||||||
val chain_id: string
|
val chain_id: string
|
||||||
|
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
(* *)
|
(* *)
|
||||||
(**************************************************************************)
|
(**************************************************************************)
|
||||||
|
|
||||||
|
type Base58.data += Encrypted_ed25519 of MBytes.t
|
||||||
|
type Base58.data += Encrypted_secp256k1 of MBytes.t
|
||||||
|
type Base58.data += Encrypted_p256 of MBytes.t
|
||||||
|
|
||||||
open Client_keys
|
open Client_keys
|
||||||
|
|
||||||
let scheme = "encrypted"
|
let scheme = "encrypted"
|
||||||
@ -19,31 +23,99 @@ module Raw = struct
|
|||||||
(* Fixed zero nonce *)
|
(* Fixed zero nonce *)
|
||||||
let nonce = Crypto_box.zero_nonce
|
let nonce = Crypto_box.zero_nonce
|
||||||
|
|
||||||
|
(* Secret keys for Ed25519, secp256k1, P256 are 32 bytes long. *)
|
||||||
|
let encrypted_size = Crypto_box.boxzerobytes + 32
|
||||||
|
|
||||||
let pbkdf ~salt ~password =
|
let pbkdf ~salt ~password =
|
||||||
Cstruct.to_bigarray
|
Cstruct.to_bigarray
|
||||||
(Pbkdf.pbkdf2 ~prf:`SHA512 ~count:2048 ~dk_len:32l
|
(Pbkdf.pbkdf2 ~prf:`SHA512 ~count:32768 ~dk_len:32l
|
||||||
~salt: (Cstruct.of_bigarray salt)
|
~salt: (Cstruct.of_bigarray salt)
|
||||||
~password: (Cstruct.of_bigarray password))
|
~password: (Cstruct.of_bigarray password))
|
||||||
|
|
||||||
let encrypt ~password sk =
|
let encrypt ~password sk =
|
||||||
let salt = Rand.generate salt_len in
|
let salt = Rand.generate salt_len in
|
||||||
let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~password ~salt) in
|
|
||||||
let msg = Data_encoding.Binary.to_bytes_exn Signature.Secret_key.encoding sk in
|
|
||||||
let encrypted_passwd = Crypto_box.Secretbox.box key msg nonce in
|
|
||||||
MBytes.concat "" [ salt ; encrypted_passwd ]
|
|
||||||
|
|
||||||
let decrypt ~password ~encrypted_sk =
|
|
||||||
let len = MBytes.length encrypted_sk in
|
|
||||||
let salt = MBytes.sub encrypted_sk 0 salt_len in
|
|
||||||
let encrypted_sk = MBytes.sub encrypted_sk salt_len (len - salt_len) in
|
|
||||||
let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~salt ~password) in
|
let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~salt ~password) in
|
||||||
match Crypto_box.Secretbox.box_open key encrypted_sk nonce with
|
let msg =
|
||||||
| None -> return_none
|
match (sk : Signature.secret_key) with
|
||||||
| Some bytes ->
|
| Ed25519 sk ->
|
||||||
match Data_encoding.Binary.of_bytes Signature.Secret_key.encoding bytes with
|
Data_encoding.Binary.to_bytes_exn Ed25519.Secret_key.encoding sk
|
||||||
| None -> failwith "Corrupted wallet, deciphered key is invalid"
|
| Secp256k1 sk ->
|
||||||
| Some sk -> return_some sk
|
Data_encoding.Binary.to_bytes_exn Secp256k1.Secret_key.encoding sk
|
||||||
|
| P256 sk ->
|
||||||
|
Data_encoding.Binary.to_bytes_exn P256.Secret_key.encoding sk in
|
||||||
|
MBytes.concat "" [ salt ;
|
||||||
|
Crypto_box.Secretbox.box key msg nonce ]
|
||||||
|
|
||||||
|
let decrypt algo ~password ~encrypted_sk =
|
||||||
|
let salt = MBytes.sub encrypted_sk 0 salt_len in
|
||||||
|
let encrypted_sk =
|
||||||
|
MBytes.sub encrypted_sk salt_len encrypted_size in
|
||||||
|
let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~salt ~password) in
|
||||||
|
match Crypto_box.Secretbox.box_open key encrypted_sk nonce, algo with
|
||||||
|
| None, _ -> return_none
|
||||||
|
| Some bytes, Signature.Ed25519 -> begin
|
||||||
|
match Data_encoding.Binary.of_bytes Ed25519.Secret_key.encoding bytes with
|
||||||
|
| Some sk -> return_some (Ed25519 sk : Signature.Secret_key.t)
|
||||||
|
| None -> failwith "Corrupted wallet, deciphered key is not a \
|
||||||
|
valid Ed25519 secret key"
|
||||||
|
end
|
||||||
|
| Some bytes, Signature.Secp256k1 -> begin
|
||||||
|
match Data_encoding.Binary.of_bytes Secp256k1.Secret_key.encoding bytes with
|
||||||
|
| Some sk -> return_some (Secp256k1 sk : Signature.Secret_key.t)
|
||||||
|
| None -> failwith "Corrupted wallet, deciphered key is not a \
|
||||||
|
valid Secp256k1 secret key"
|
||||||
|
end
|
||||||
|
| Some bytes, Signature.P256 -> begin
|
||||||
|
match Data_encoding.Binary.of_bytes P256.Secret_key.encoding bytes with
|
||||||
|
| Some sk -> return_some (P256 sk : Signature.Secret_key.t)
|
||||||
|
| None -> failwith "Corrupted wallet, deciphered key is not a \
|
||||||
|
valid P256 secret key"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Encodings = struct
|
||||||
|
|
||||||
|
let ed25519 =
|
||||||
|
let length =
|
||||||
|
Hacl.Sign.skbytes + Crypto_box.boxzerobytes + Raw.salt_len in
|
||||||
|
Base58.register_encoding
|
||||||
|
~prefix: Base58.Prefix.ed25519_encrypted_seed
|
||||||
|
~length
|
||||||
|
~to_raw: (fun sk -> MBytes.to_string sk)
|
||||||
|
~of_raw: (fun buf ->
|
||||||
|
if String.length buf <> length then None
|
||||||
|
else Some (MBytes.of_string buf))
|
||||||
|
~wrap: (fun sk -> Encrypted_ed25519 sk)
|
||||||
|
|
||||||
|
let secp256k1 =
|
||||||
|
let open Libsecp256k1.External in
|
||||||
|
let length =
|
||||||
|
Key.secret_bytes + Crypto_box.boxzerobytes +Raw.salt_len in
|
||||||
|
Base58.register_encoding
|
||||||
|
~prefix: Base58.Prefix.secp256k1_encrypted_secret_key
|
||||||
|
~length
|
||||||
|
~to_raw: (fun sk -> MBytes.to_string sk)
|
||||||
|
~of_raw: (fun buf ->
|
||||||
|
if String.length buf <> length then None
|
||||||
|
else Some (MBytes.of_string buf))
|
||||||
|
~wrap: (fun sk -> Encrypted_secp256k1 sk)
|
||||||
|
|
||||||
|
let p256 =
|
||||||
|
let length =
|
||||||
|
Uecc.(sk_size secp256r1) + Crypto_box.boxzerobytes + Raw.salt_len in
|
||||||
|
Base58.register_encoding
|
||||||
|
~prefix: Base58.Prefix.p256_encrypted_secret_key
|
||||||
|
~length
|
||||||
|
~to_raw: (fun sk -> MBytes.to_string sk)
|
||||||
|
~of_raw: (fun buf ->
|
||||||
|
if String.length buf <> length then None
|
||||||
|
else Some (MBytes.of_string buf))
|
||||||
|
~wrap: (fun sk -> Encrypted_p256 sk)
|
||||||
|
|
||||||
|
let () =
|
||||||
|
Base58.check_encoded_prefix ed25519 "edesk" 88 ;
|
||||||
|
Base58.check_encoded_prefix secp256k1 "spesk" 88 ;
|
||||||
|
Base58.check_encoded_prefix p256 "p2esk" 88
|
||||||
end
|
end
|
||||||
|
|
||||||
let decrypted = Hashtbl.create 13
|
let decrypted = Hashtbl.create 13
|
||||||
@ -51,9 +123,8 @@ let passwords = ref []
|
|||||||
|
|
||||||
let rec interactive_decrypt_loop
|
let rec interactive_decrypt_loop
|
||||||
(cctxt : #Client_context.prompter)
|
(cctxt : #Client_context.prompter)
|
||||||
?name ~encrypted_sk =
|
?name ~encrypted_sk algo =
|
||||||
begin
|
begin match name with
|
||||||
match name with
|
|
||||||
| None ->
|
| None ->
|
||||||
cctxt#prompt_password
|
cctxt#prompt_password
|
||||||
"Enter password for encrypted key: "
|
"Enter password for encrypted key: "
|
||||||
@ -61,30 +132,35 @@ let rec interactive_decrypt_loop
|
|||||||
cctxt#prompt_password
|
cctxt#prompt_password
|
||||||
"Enter password for encrypted key \"%s\": " name
|
"Enter password for encrypted key \"%s\": " name
|
||||||
end >>=? fun password ->
|
end >>=? fun password ->
|
||||||
Raw.decrypt ~password ~encrypted_sk >>=? function
|
Raw.decrypt algo ~password ~encrypted_sk >>=? function
|
||||||
| None ->
|
|
||||||
interactive_decrypt_loop cctxt ?name ~encrypted_sk
|
|
||||||
| Some sk ->
|
| Some sk ->
|
||||||
passwords := password :: !passwords ;
|
passwords := password :: !passwords ;
|
||||||
return sk
|
return sk
|
||||||
|
| None ->
|
||||||
|
interactive_decrypt_loop cctxt ?name ~encrypted_sk algo
|
||||||
|
|
||||||
let rec noninteractice_decrypt_loop ~encrypted_sk = function
|
let rec noninteractice_decrypt_loop algo ~encrypted_sk = function
|
||||||
| [] -> return_none
|
| [] -> return_none
|
||||||
| password :: passwords ->
|
| password :: passwords ->
|
||||||
Raw.decrypt ~password ~encrypted_sk >>=? function
|
Raw.decrypt algo ~password ~encrypted_sk >>=? function
|
||||||
| None -> noninteractice_decrypt_loop ~encrypted_sk passwords
|
| None -> noninteractice_decrypt_loop algo ~encrypted_sk passwords
|
||||||
| Some sk -> return_some sk
|
| Some sk -> return_some sk
|
||||||
|
|
||||||
let decrypt_payload cctxt ?name encrypted_sk =
|
let decrypt_payload cctxt ?name encrypted_sk =
|
||||||
match Base58.safe_decode encrypted_sk with
|
begin match Base58.decode encrypted_sk with
|
||||||
| None -> failwith "Not a Base58 encoded encrypted key"
|
| Some (Encrypted_ed25519 encrypted_sk) ->
|
||||||
| Some encrypted_sk ->
|
return (Signature.Ed25519, encrypted_sk)
|
||||||
let encrypted_sk = MBytes.of_string encrypted_sk in
|
| Some (Encrypted_secp256k1 encrypted_sk) ->
|
||||||
noninteractice_decrypt_loop ~encrypted_sk !passwords >>=? function
|
return (Signature.Secp256k1, encrypted_sk)
|
||||||
| Some sk -> return sk
|
| Some (Encrypted_p256 encrypted_sk) ->
|
||||||
| None -> interactive_decrypt_loop cctxt ?name ~encrypted_sk
|
return (Signature.P256, encrypted_sk)
|
||||||
|
| _ -> failwith "Not a Base58Check-encoded encrypted key"
|
||||||
|
end >>=? fun (algo, encrypted_sk) ->
|
||||||
|
noninteractice_decrypt_loop algo ~encrypted_sk !passwords >>=? function
|
||||||
|
| Some sk -> return sk
|
||||||
|
| None -> interactive_decrypt_loop cctxt ?name ~encrypted_sk algo
|
||||||
|
|
||||||
let decrypt cctxt ?name sk_uri =
|
let decrypt (cctxt : #Client_context.prompter) ?name sk_uri =
|
||||||
let payload = Uri.path (sk_uri : sk_uri :> Uri.t) in
|
let payload = Uri.path (sk_uri : sk_uri :> Uri.t) in
|
||||||
decrypt_payload cctxt ?name payload >>=? fun sk ->
|
decrypt_payload cctxt ?name payload >>=? fun sk ->
|
||||||
Hashtbl.replace decrypted sk_uri sk ;
|
Hashtbl.replace decrypted sk_uri sk ;
|
||||||
@ -114,7 +190,11 @@ let rec read_passphrase (cctxt : #Client_context.io) =
|
|||||||
let encrypt cctxt sk =
|
let encrypt cctxt sk =
|
||||||
read_passphrase cctxt >>=? fun password ->
|
read_passphrase cctxt >>=? fun password ->
|
||||||
let payload = Raw.encrypt ~password sk in
|
let payload = Raw.encrypt ~password sk in
|
||||||
let path = Base58.safe_encode (MBytes.to_string payload) in
|
let encoding = match sk with
|
||||||
|
| Ed25519 _ -> Encodings.ed25519
|
||||||
|
| Secp256k1 _ -> Encodings.secp256k1
|
||||||
|
| P256 _ -> Encodings.p256 in
|
||||||
|
let path = Base58.simple_encode encoding payload in
|
||||||
let sk_uri = Client_keys.make_sk_uri (Uri.make ~scheme ~path ()) in
|
let sk_uri = Client_keys.make_sk_uri (Uri.make ~scheme ~path ()) in
|
||||||
Hashtbl.replace decrypted sk_uri sk ;
|
Hashtbl.replace decrypted sk_uri sk ;
|
||||||
return sk_uri
|
return sk_uri
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
module Make(C : sig val cctxt: Client_context.prompter end) : Client_keys.SIGNER
|
module Make(C : sig val cctxt: Client_context.prompter end) : Client_keys.SIGNER
|
||||||
|
|
||||||
val decrypt:
|
val decrypt:
|
||||||
#Client_context.io_wallet ->
|
#Client_context.prompter ->
|
||||||
?name:string ->
|
?name:string ->
|
||||||
Client_keys.sk_uri -> Signature.secret_key tzresult Lwt.t
|
Client_keys.sk_uri -> Signature.secret_key tzresult Lwt.t
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user