rippled
WalletPropose.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2014 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/strHex.h>
21 #include <ripple/net/RPCErr.h>
22 #include <ripple/protocol/ErrorCodes.h>
23 #include <ripple/protocol/KeyType.h>
24 #include <ripple/protocol/PublicKey.h>
25 #include <ripple/protocol/SecretKey.h>
26 #include <ripple/protocol/Seed.h>
27 #include <ripple/protocol/jss.h>
28 #include <ripple/rpc/Context.h>
29 #include <ripple/rpc/handlers/WalletPropose.h>
30 #include <ripple/rpc/impl/RPCHelpers.h>
31 #include <cmath>
32 #include <ed25519.h>
33 #include <map>
34 
35 namespace ripple {
36 
37 double
39 {
40  // First, we calculate the Shannon entropy. This gives
41  // the average number of bits per symbol that we would
42  // need to encode the input.
44 
45  for (auto const& c : input)
46  freq[c]++;
47 
48  double se = 0.0;
49 
50  for (auto const& [_, f] : freq)
51  {
52  (void)_;
53  auto x = f / input.length();
54  se += (x)*log2(x);
55  }
56 
57  // We multiply it by the length, to get an estimate of
58  // the number of bits in the input. We floor because it
59  // is better to be conservative.
60  return std::floor(-se * input.length());
61 }
62 
63 // {
64 // passphrase: <string>
65 // }
68 {
69  return walletPropose(context.params);
70 }
71 
73 walletPropose(Json::Value const& params)
74 {
75  std::optional<KeyType> keyType;
77  bool rippleLibSeed = false;
78 
79  if (params.isMember(jss::key_type))
80  {
81  if (!params[jss::key_type].isString())
82  {
83  return RPC::expected_field_error(jss::key_type, "string");
84  }
85 
86  keyType = keyTypeFromString(params[jss::key_type].asString());
87 
88  if (!keyType)
90  }
91 
92  // ripple-lib encodes seed used to generate an Ed25519 wallet in a
93  // non-standard way. While we never encode seeds that way, we try
94  // to detect such keys to avoid user confusion.
95  {
96  if (params.isMember(jss::passphrase))
97  seed = RPC::parseRippleLibSeed(params[jss::passphrase]);
98  else if (params.isMember(jss::seed))
99  seed = RPC::parseRippleLibSeed(params[jss::seed]);
100 
101  if (seed)
102  {
103  rippleLibSeed = true;
104 
105  // If the user *explicitly* requests a key type other than
106  // Ed25519 we return an error.
108  return rpcError(rpcBAD_SEED);
109 
110  keyType = KeyType::ed25519;
111  }
112  }
113 
114  if (!seed)
115  {
116  if (params.isMember(jss::passphrase) || params.isMember(jss::seed) ||
117  params.isMember(jss::seed_hex))
118  {
119  Json::Value err;
120 
121  seed = RPC::getSeedFromRPC(params, err);
122 
123  if (!seed)
124  return err;
125  }
126  else
127  {
128  seed = randomSeed();
129  }
130  }
131 
132  if (!keyType)
133  keyType = KeyType::secp256k1;
134 
135  auto const publicKey = generateKeyPair(*keyType, *seed).first;
136 
138 
139  auto const seed1751 = seedAs1751(*seed);
140  auto const seedHex = strHex(*seed);
141  auto const seedBase58 = toBase58(*seed);
142 
143  obj[jss::master_seed] = seedBase58;
144  obj[jss::master_seed_hex] = seedHex;
145  obj[jss::master_key] = seed1751;
146  obj[jss::account_id] = toBase58(calcAccountID(publicKey));
147  obj[jss::public_key] = toBase58(TokenType::AccountPublic, publicKey);
148  obj[jss::key_type] = to_string(*keyType);
149  obj[jss::public_key_hex] = strHex(publicKey);
150 
151  // If a passphrase was specified, and it was hashed and used as a seed
152  // run a quick entropy check and add an appropriate warning, because
153  // "brain wallets" can be easily attacked.
154  if (!rippleLibSeed && params.isMember(jss::passphrase))
155  {
156  auto const passphrase = params[jss::passphrase].asString();
157 
158  if (passphrase != seed1751 && passphrase != seedBase58 &&
159  passphrase != seedHex)
160  {
161  // 80 bits of entropy isn't bad, but it's better to
162  // err on the side of caution and be conservative.
163  if (estimate_entropy(passphrase) < 80.0)
164  obj[jss::warning] =
165  "This wallet was generated using a user-supplied "
166  "passphrase that has low entropy and is vulnerable "
167  "to brute-force attacks.";
168  else
169  obj[jss::warning] =
170  "This wallet was generated using a user-supplied "
171  "passphrase. It may be vulnerable to brute-force "
172  "attacks.";
173  }
174  }
175 
176  return obj;
177 }
178 
179 } // namespace ripple
std::floor
T floor(T... args)
ripple::RPC::JsonContext
Definition: Context.h:53
std::string
STL class.
ripple::rpcINVALID_PARAMS
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
ripple::keyTypeFromString
std::optional< KeyType > keyTypeFromString(std::string const &s)
Definition: KeyType.h:34
std::optional::value_or
T value_or(T... args)
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
cmath
ripple::generateKeyPair
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
Definition: SecretKey.cpp:351
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:328
ripple::KeyType::ed25519
@ ed25519
ripple::RPC::parseRippleLibSeed
std::optional< Seed > parseRippleLibSeed(Json::Value const &value)
Definition: RPCHelpers.cpp:771
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::rpcBAD_SEED
@ rpcBAD_SEED
Definition: ErrorCodes.h:99
ripple::seedAs1751
std::string seedAs1751(Seed const &seed)
Encode a Seed in RFC1751 format.
Definition: Seed.cpp:128
ripple::calcAccountID
AccountID calcAccountID(PublicKey const &pk)
Definition: AccountID.cpp:158
ripple::doWalletPropose
Json::Value doWalletPropose(RPC::JsonContext &)
Definition: WalletPropose.cpp:67
ripple::randomSeed
Seed randomSeed()
Create a seed using secure random numbers.
Definition: Seed.cpp:59
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
map
ripple::KeyType::secp256k1
@ secp256k1
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::RPC::getSeedFromRPC
std::optional< Seed > getSeedFromRPC(Json::Value const &params, Json::Value &error)
Definition: RPCHelpers.cpp:790
ripple::TokenType::AccountPublic
@ AccountPublic
std::optional
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
ripple::walletPropose
Json::Value walletPropose(Json::Value const &params)
Definition: WalletPropose.cpp:73
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
ripple::estimate_entropy
double estimate_entropy(std::string const &input)
Definition: WalletPropose.cpp:38
Json::Value
Represents a JSON value.
Definition: json_value.h:145
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469