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 <boost/optional.hpp>
32 #include <cmath>
33 #include <ed25519-donna/ed25519.h>
34 #include <map>
35 
36 namespace ripple {
37 
38 double
40 {
41  // First, we calculate the Shannon entropy. This gives
42  // the average number of bits per symbol that we would
43  // need to encode the input.
45 
46  for (auto const& c : input)
47  freq[c]++;
48 
49  double se = 0.0;
50 
51  for (auto const& [_, f] : freq)
52  {
53  (void)_;
54  auto x = f / input.length();
55  se += (x)*log2(x);
56  }
57 
58  // We multiply it by the length, to get an estimate of
59  // the number of bits in the input. We floor because it
60  // is better to be conservative.
61  return std::floor(-se * input.length());
62 }
63 
64 // {
65 // passphrase: <string>
66 // }
69 {
70  return walletPropose(context.params);
71 }
72 
74 walletPropose(Json::Value const& params)
75 {
76  boost::optional<KeyType> keyType;
77  boost::optional<Seed> seed;
78  bool rippleLibSeed = false;
79 
80  if (params.isMember(jss::key_type))
81  {
82  if (!params[jss::key_type].isString())
83  {
84  return RPC::expected_field_error(jss::key_type, "string");
85  }
86 
87  keyType = keyTypeFromString(params[jss::key_type].asString());
88 
89  if (!keyType)
91  }
92 
93  // ripple-lib encodes seed used to generate an Ed25519 wallet in a
94  // non-standard way. While we never encode seeds that way, we try
95  // to detect such keys to avoid user confusion.
96  {
97  if (params.isMember(jss::passphrase))
98  seed = RPC::parseRippleLibSeed(params[jss::passphrase]);
99  else if (params.isMember(jss::seed))
100  seed = RPC::parseRippleLibSeed(params[jss::seed]);
101 
102  if (seed)
103  {
104  rippleLibSeed = true;
105 
106  // If the user *explicitly* requests a key type other than
107  // Ed25519 we return an error.
108  if (keyType.value_or(KeyType::ed25519) != KeyType::ed25519)
109  return rpcError(rpcBAD_SEED);
110 
111  keyType = KeyType::ed25519;
112  }
113  }
114 
115  if (!seed)
116  {
117  if (params.isMember(jss::passphrase) || params.isMember(jss::seed) ||
118  params.isMember(jss::seed_hex))
119  {
120  Json::Value err;
121 
122  seed = RPC::getSeedFromRPC(params, err);
123 
124  if (!seed)
125  return err;
126  }
127  else
128  {
129  seed = randomSeed();
130  }
131  }
132 
133  if (!keyType)
134  keyType = KeyType::secp256k1;
135 
136  auto const publicKey = generateKeyPair(*keyType, *seed).first;
137 
139 
140  auto const seed1751 = seedAs1751(*seed);
141  auto const seedHex = strHex(*seed);
142  auto const seedBase58 = toBase58(*seed);
143 
144  obj[jss::master_seed] = seedBase58;
145  obj[jss::master_seed_hex] = seedHex;
146  obj[jss::master_key] = seed1751;
147  obj[jss::account_id] = toBase58(calcAccountID(publicKey));
148  obj[jss::public_key] = toBase58(TokenType::AccountPublic, publicKey);
149  obj[jss::key_type] = to_string(*keyType);
150  obj[jss::public_key_hex] = strHex(publicKey);
151 
152  // If a passphrase was specified, and it was hashed and used as a seed
153  // run a quick entropy check and add an appropriate warning, because
154  // "brain wallets" can be easily attacked.
155  if (!rippleLibSeed && params.isMember(jss::passphrase))
156  {
157  auto const passphrase = params[jss::passphrase].asString();
158 
159  if (passphrase != seed1751 && passphrase != seedBase58 &&
160  passphrase != seedHex)
161  {
162  // 80 bits of entropy isn't bad, but it's better to
163  // err on the side of caution and be conservative.
164  if (estimate_entropy(passphrase) < 80.0)
165  obj[jss::warning] =
166  "This wallet was generated using a user-supplied "
167  "passphrase that has low entropy and is vulnerable "
168  "to brute-force attacks.";
169  else
170  obj[jss::warning] =
171  "This wallet was generated using a user-supplied "
172  "passphrase. It may be vulnerable to brute-force "
173  "attacks.";
174  }
175  }
176 
177  return obj;
178 }
179 
180 } // 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::RPC::parseRippleLibSeed
boost::optional< Seed > parseRippleLibSeed(Json::Value const &value)
Definition: RPCHelpers.cpp:631
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:29
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:45
cmath
ripple::generateKeyPair
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
Definition: SecretKey.cpp:243
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:309
ripple::keyTypeFromString
boost::optional< KeyType > keyTypeFromString(std::string const &s)
Definition: KeyType.h:34
ripple::KeyType::ed25519
@ ed25519
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:127
ripple::calcAccountID
AccountID calcAccountID(PublicKey const &pk)
Definition: AccountID.cpp:80
ripple::doWalletPropose
Json::Value doWalletPropose(RPC::JsonContext &)
Definition: WalletPropose.cpp:68
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::rpcError
Json::Value rpcError(int iError, Json::Value jvResult)
Definition: RPCErr.cpp:29
ripple::KeyType::secp256k1
@ secp256k1
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::TokenType::AccountPublic
@ AccountPublic
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:45
ripple::walletPropose
Json::Value walletPropose(Json::Value const &params)
Definition: WalletPropose.cpp:74
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
ripple::estimate_entropy
double estimate_entropy(std::string const &input)
Definition: WalletPropose.cpp:39
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
ripple::RPC::getSeedFromRPC
boost::optional< Seed > getSeedFromRPC(Json::Value const &params, Json::Value &error)
Definition: RPCHelpers.cpp:650