diff --git a/src/lib_client_commands/client_keys_commands.ml b/src/lib_client_commands/client_keys_commands.ml index 4d5748a11..dd0d4a495 100644 --- a/src/lib_client_commands/client_keys_commands.ml +++ b/src/lib_client_commands/client_keys_commands.ml @@ -13,6 +13,17 @@ let group = { Clic.name = "keys" ; title = "Commands for managing the wallet of cryptographic keys" } +let encrypted_switch () = + if List.exists + (fun (_, (module Signer : Client_keys.SIGNER)) -> + Signer.scheme = Tezos_signer_backends.Unencrypted.scheme) + (Client_keys.registered_signers ()) then + Clic.switch + ~long:"encrypted" + ~doc:("Encrypt the key on-disk") () + else + Clic.constant true + let sig_algo_arg = Clic.default_arg ~doc:"use custom signature algorithm" @@ -23,7 +34,7 @@ let sig_algo_arg = (Signature.algo_param ()) let gen_keys_containing - ?(prefix=false) ?(force=false) + ?(encrypted = false) ?(prefix=false) ?(force=false) ~containing ~name (cctxt : #Client_context.io_wallet) = let unrepresentable = List.filter (fun s -> not @@ Base58.Alphabet.all_in_alphabet Base58.Alphabet.bitcoin s) containing in @@ -65,7 +76,12 @@ let gen_keys_containing if matches hash then let pk_uri = Tezos_signer_backends.Unencrypted.make_pk public_key in - let sk_uri = Tezos_signer_backends.Unencrypted.make_sk secret_key in + begin + if encrypted then + Tezos_signer_backends.Encrypted.encrypt cctxt secret_key + else + return (Tezos_signer_backends.Unencrypted.make_sk secret_key) + end >>=? fun sk_uri -> register_key cctxt ~force (public_key_hash, pk_uri, sk_uri) name >>=? fun () -> return hash @@ -111,33 +127,39 @@ let commands () : Client_context.io_wallet Clic.command list = n S.title Format.pp_print_text S.description) signers >>= return) ; - command ~group ~desc: "Generate a pair of (unencrypted) keys." - (args2 (Secret_key.force_switch ()) sig_algo_arg) + command ~group ~desc: "Generate a pair of keys." + (args3 (Secret_key.force_switch ()) sig_algo_arg (encrypted_switch ())) (prefixes [ "gen" ; "keys" ] @@ Secret_key.fresh_alias_param @@ stop) - (fun (force, algo) name (cctxt : #Client_context.io_wallet) -> + (fun (force, algo, encrypted) name (cctxt : Client_context.io_wallet) -> Secret_key.of_fresh cctxt force name >>=? fun name -> let (pkh, pk, sk) = Signature.generate_key ~algo () in let pk_uri = Tezos_signer_backends.Unencrypted.make_pk pk in - let sk_uri = Tezos_signer_backends.Unencrypted.make_sk sk in + begin + if encrypted then + Tezos_signer_backends.Encrypted.encrypt cctxt sk + else + return (Tezos_signer_backends.Unencrypted.make_sk sk) + end >>=? fun sk_uri -> register_key cctxt ~force (pkh, pk_uri, sk_uri) name) ; - command ~group ~desc: "Generate (unencrypted) keys including the given string." - (args2 + command ~group ~desc: "Generate keys including the given string." + (args3 (switch ~long:"prefix" ~short:'P' ~doc:"the key must begin with tz1[word]" ()) - (force_switch ())) + (force_switch ()) + (encrypted_switch ())) (prefixes [ "gen" ; "vanity" ; "keys" ] @@ Public_key_hash.fresh_alias_param @@ prefix "matching" @@ (seq_of_param @@ string ~name:"words" ~desc:"string key must contain one of these words")) - (fun (prefix, force) name containing (cctxt : #Client_context.io_wallet) -> + (fun (prefix, force, encrypted) name containing (cctxt : Client_context.io_wallet) -> Public_key_hash.of_fresh cctxt force name >>=? fun name -> - gen_keys_containing ~force ~prefix ~containing ~name cctxt) ; + gen_keys_containing ~encrypted ~force ~prefix ~containing ~name cctxt) ; command ~group ~desc: "Add a secret key to the wallet." (args1 (Secret_key.force_switch ())) diff --git a/src/lib_client_commands/client_keys_commands.mli b/src/lib_client_commands/client_keys_commands.mli index e4d448d02..59a4999ce 100644 --- a/src/lib_client_commands/client_keys_commands.mli +++ b/src/lib_client_commands/client_keys_commands.mli @@ -8,3 +8,5 @@ (**************************************************************************) val commands: unit -> Client_context.io_wallet Clic.command list + +val encrypted_switch: unit -> (bool, 'a) Clic.arg diff --git a/src/proto_alpha/lib_client/client_proto_context.ml b/src/proto_alpha/lib_client/client_proto_context.ml index eca048878..eb2305a85 100644 --- a/src/proto_alpha/lib_client/client_proto_context.ml +++ b/src/proto_alpha/lib_client/client_proto_context.ml @@ -330,7 +330,7 @@ let read_key key = return (pkh, pk, sk) let claim_commitment (cctxt : #Proto_alpha.full) - ?confirmations ?force block key name = + ?(encrypted = false) ?confirmations ?force block key name = read_key key >>=? fun (pkh, pk, sk) -> fail_unless (Signature.Public_key_hash.equal pkh (Ed25519 key.pkh)) (failure "@[Inconsistent activation key:@ \ @@ -346,7 +346,12 @@ let claim_commitment (cctxt : #Proto_alpha.full) cctxt ~chain_id:bi.chain_id bytes >>=? fun oph -> operation_submitted_message cctxt oph >>=? fun () -> let pk_uri = Tezos_signer_backends.Unencrypted.make_pk pk in - let sk_uri = Tezos_signer_backends.Unencrypted.make_sk sk in + begin + if encrypted then + Tezos_signer_backends.Encrypted.encrypt cctxt sk + else + return (Tezos_signer_backends.Unencrypted.make_sk sk) + end >>=? fun sk_uri -> begin match confirmations with | None -> diff --git a/src/proto_alpha/lib_client/client_proto_context.mli b/src/proto_alpha/lib_client/client_proto_context.mli index 9f3c87537..d2954c151 100644 --- a/src/proto_alpha/lib_client/client_proto_context.mli +++ b/src/proto_alpha/lib_client/client_proto_context.mli @@ -155,6 +155,7 @@ val activation_key_encoding: activation_key Data_encoding.t val claim_commitment: #Proto_alpha.full -> + ?encrypted:bool -> ?confirmations:int -> ?force:bool -> Block_services.block -> diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index a11f621f5..02546b0ca 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -261,7 +261,10 @@ let commands () = end; command ~group ~desc:"Register and activate a predefined account using the provided activation key." - (args2 (Secret_key.force_switch ()) (Client_proto_args.no_confirmation)) + (args3 + (Secret_key.force_switch ()) + (Client_proto_args.no_confirmation) + (Client_keys_commands.encrypted_switch ())) (prefixes [ "activate" ; "account" ] @@ Secret_key.fresh_alias_param @@ prefixes [ "with" ] @@ -269,21 +272,24 @@ let commands () = ~desc:"Activation key (as JSON file) obtained from the Tezos foundation (or the Alphanet faucet)." file_parameter @@ stop) - (fun (force, no_confirmation) name activation_key_file cctxt -> - Secret_key.of_fresh cctxt force name >>=? fun name -> - Lwt_utils_unix.Json.read_file activation_key_file >>=? fun json -> - match Data_encoding.Json.destruct - Client_proto_context.activation_key_encoding - json with - | exception (Data_encoding.Json.Cannot_destruct _ as exn) -> - Format.kasprintf (fun s -> failwith "%s" s) - "Invalid activation file: %a %a" - (fun ppf -> Data_encoding.Json.print_error ppf) exn - Data_encoding.Json.pp json - | key -> - let confirmations = - if no_confirmation then None else Some 0 in - claim_commitment cctxt cctxt#block ?confirmations ~force key name + (fun + (force, no_confirmation, encrypted) + name activation_key_file cctxt -> + Secret_key.of_fresh cctxt force name >>=? fun name -> + Lwt_utils_unix.Json.read_file activation_key_file >>=? fun json -> + match Data_encoding.Json.destruct + Client_proto_context.activation_key_encoding + json with + | exception (Data_encoding.Json.Cannot_destruct _ as exn) -> + Format.kasprintf (fun s -> failwith "%s" s) + "Invalid activation file: %a %a" + (fun ppf -> Data_encoding.Json.print_error ppf) exn + Data_encoding.Json.pp json + | key -> + let confirmations = + if no_confirmation then None else Some 0 in + claim_commitment cctxt cctxt#block + ~encrypted ?confirmations ~force key name ); command ~group:alphanet ~desc: "Activate a protocol (Alphanet dictator only)."