rippled
Loading...
Searching...
No Matches
WalletPropose.cpp
1#include <xrpld/rpc/Context.h>
2#include <xrpld/rpc/detail/RPCHelpers.h>
3#include <xrpld/rpc/handlers/WalletPropose.h>
4
5#include <xrpl/basics/strHex.h>
6#include <xrpl/protocol/ErrorCodes.h>
7#include <xrpl/protocol/KeyType.h>
8#include <xrpl/protocol/PublicKey.h>
9#include <xrpl/protocol/RPCErr.h>
10#include <xrpl/protocol/SecretKey.h>
11#include <xrpl/protocol/Seed.h>
12#include <xrpl/protocol/jss.h>
13
14#include <cmath>
15#include <map>
16
17namespace ripple {
18
19double
21{
22 // First, we calculate the Shannon entropy. This gives
23 // the average number of bits per symbol that we would
24 // need to encode the input.
26
27 for (auto const& c : input)
28 freq[c]++;
29
30 double se = 0.0;
31
32 for (auto const& [_, f] : freq)
33 {
34 (void)_;
35 auto x = f / input.length();
36 se += (x)*log2(x);
37 }
38
39 // We multiply it by the length, to get an estimate of
40 // the number of bits in the input. We floor because it
41 // is better to be conservative.
42 return std::floor(-se * input.length());
43}
44
45// {
46// passphrase: <string>
47// }
50{
51 return walletPropose(context.params);
52}
53
56{
59 bool rippleLibSeed = false;
60
61 if (params.isMember(jss::key_type))
62 {
63 if (!params[jss::key_type].isString())
64 {
65 return RPC::expected_field_error(jss::key_type, "string");
66 }
67
68 keyType = keyTypeFromString(params[jss::key_type].asString());
69
70 if (!keyType)
72 }
73
74 // ripple-lib encodes seed used to generate an Ed25519 wallet in a
75 // non-standard way. While we never encode seeds that way, we try
76 // to detect such keys to avoid user confusion.
77 {
78 if (params.isMember(jss::passphrase))
79 seed = RPC::parseRippleLibSeed(params[jss::passphrase]);
80 else if (params.isMember(jss::seed))
81 seed = RPC::parseRippleLibSeed(params[jss::seed]);
82
83 if (seed)
84 {
85 rippleLibSeed = true;
86
87 // If the user *explicitly* requests a key type other than
88 // Ed25519 we return an error.
90 return rpcError(rpcBAD_SEED);
91
92 keyType = KeyType::ed25519;
93 }
94 }
95
96 if (!seed)
97 {
98 if (params.isMember(jss::passphrase) || params.isMember(jss::seed) ||
99 params.isMember(jss::seed_hex))
100 {
101 Json::Value err;
102
103 seed = RPC::getSeedFromRPC(params, err);
104
105 if (!seed)
106 return err;
107 }
108 else
109 {
110 seed = randomSeed();
111 }
112 }
113
114 if (!keyType)
115 keyType = KeyType::secp256k1;
116
117 auto const publicKey = generateKeyPair(*keyType, *seed).first;
118
120
121 auto const seed1751 = seedAs1751(*seed);
122 auto const seedHex = strHex(*seed);
123 auto const seedBase58 = toBase58(*seed);
124
125 obj[jss::master_seed] = seedBase58;
126 obj[jss::master_seed_hex] = seedHex;
127 obj[jss::master_key] = seed1751;
128 obj[jss::account_id] = toBase58(calcAccountID(publicKey));
129 obj[jss::public_key] = toBase58(TokenType::AccountPublic, publicKey);
130 obj[jss::key_type] = to_string(*keyType);
131 obj[jss::public_key_hex] = strHex(publicKey);
132
133 // If a passphrase was specified, and it was hashed and used as a seed
134 // run a quick entropy check and add an appropriate warning, because
135 // "brain wallets" can be easily attacked.
136 if (!rippleLibSeed && params.isMember(jss::passphrase))
137 {
138 auto const passphrase = params[jss::passphrase].asString();
139
140 if (passphrase != seed1751 && passphrase != seedBase58 &&
141 passphrase != seedHex)
142 {
143 // 80 bits of entropy isn't bad, but it's better to
144 // err on the side of caution and be conservative.
145 if (estimate_entropy(passphrase) < 80.0)
146 obj[jss::warning] =
147 "This wallet was generated using a user-supplied "
148 "passphrase that has low entropy and is vulnerable "
149 "to brute-force attacks.";
150 else
151 obj[jss::warning] =
152 "This wallet was generated using a user-supplied "
153 "passphrase. It may be vulnerable to brute-force "
154 "attacks.";
155 }
156 }
157
158 return obj;
159}
160
161} // namespace ripple
Represents a JSON value.
Definition json_value.h:131
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
T floor(T... args)
@ objectValue
object value (collection of name/value pairs).
Definition json_value.h:27
std::optional< Seed > getSeedFromRPC(Json::Value const &params, Json::Value &error)
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition ErrorCodes.h:330
std::optional< Seed > parseRippleLibSeed(Json::Value const &value)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::optional< KeyType > keyTypeFromString(std::string const &s)
Definition KeyType.h:15
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:95
@ rpcINVALID_PARAMS
Definition ErrorCodes.h:65
@ rpcBAD_SEED
Definition ErrorCodes.h:80
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
Seed randomSeed()
Create a seed using secure random numbers.
Definition Seed.cpp:47
AccountID calcAccountID(PublicKey const &pk)
Json::Value rpcError(int iError)
Definition RPCErr.cpp:12
std::string seedAs1751(Seed const &seed)
Encode a Seed in RFC1751 format.
Definition Seed.cpp:116
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:11
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
Json::Value walletPropose(Json::Value const &params)
double estimate_entropy(std::string const &input)
Json::Value doWalletPropose(RPC::JsonContext &)
T length(T... args)
T value_or(T... args)