forked from casascius/Bitcoin-Address-Utility
/
EncryptedKeyPair.cs
153 lines (132 loc) · 5.74 KB
/
EncryptedKeyPair.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BtcAddress {
/// <summary>
/// Represents an encrypted private key.
/// The only thing we are certain to have is a representation of a private key in a known format.
/// We might know the decryption key, but we might not.
/// We might know the unencrypted private key, but we might not.
/// We might know the public key, but we might not.
/// We might know the Bitcoin address, but we might not.
/// </summary>
public abstract class EncryptedKeyPair {
protected EncryptedKeyPair() { }
/// <summary>
/// The encrypted representation of the private key, validated to be in a known format.
/// Which known format depends on the derived implementation.
/// </summary>
protected string _encryptedKey;
public string EncryptedPrivateKey {
get {
return _encryptedKey;
}
}
/// <summary>
/// Contains the private key if we know it.
/// If we don't know it, this contains null.
/// </summary>
protected byte[] _privKey;
/// <summary>
/// Calculates private key and returns true if calculating private key was possible.
/// </summary>
protected virtual bool calculatePrivKey() {
return false;
}
/// <summary>
/// Returns true if the unencrypted private key is available.
/// Calling this may cause a delay of up to a few seconds while the private key is decrypted if decryption
/// is possible and necessary to determine that we have the private key.
/// Successful decryption is cached and there is no delay for subsequent checks.
/// </summary>
public virtual bool IsUnencryptedPrivateKeyAvailable() {
if (_privKey != null) return true;
if (calculatePrivKey()) return true;
return false;
}
public KeyPair GetUnencryptedPrivateKey() {
if (IsUnencryptedPrivateKeyAvailable() == false) {
throw new InvalidOperationException("Unencrypted private key is not available");
}
return new KeyPair(_privKey, compressed: IsCompressedPoint, addressType: _addressType);
}
/// <summary>
/// Contains the public key if we know it.
/// If we don't know it, this contains null.
/// </summary>
protected byte[] _pubKey;
public bool IsCompressedPoint { get; protected set; }
/// <summary>
/// Calculates public key and returns true if calculating public key was possible.
/// This might cause a delay of milliseconds if it must be computed from the public
/// key, possibly more if it leads to decrypting a private key.
/// </summary>
protected virtual bool calculatePubKey() {
if (IsUnencryptedPrivateKeyAvailable()) {
KeyPair kp = new KeyPair(_privKey, compressed: IsCompressedPoint, addressType: _addressType);
_pubKey = kp.PublicKeyBytes;
return true;
}
return false;
}
/// <summary>
/// Returns true if the public key is available.
/// Calling this may cause a delay of up to a few seconds while the private key is decrypted if decryption
/// is possible and necessary to determine that we have the public key.
/// Successful decryption is cached and there is no delay for subsequent checks.
/// </summary>
public virtual bool IsPublicKeyAvailable() {
if (_pubKey != null) return true;
if (_privKey != null) return true;
return false;
}
public PublicKey GetPublicKey() {
if (_pubKey == null) {
calculatePubKey();
if (IsPublicKeyAvailable() == false) {
throw new InvalidOperationException("Public key is not available");
}
}
return new PublicKey(_pubKey);
}
/// <summary>
/// Contains the hash160 if we know it.
/// If we don't know it, this contains null.
/// </summary>
protected byte[] _hash160;
protected virtual bool calculateHash160() {
if (IsPublicKeyAvailable()) {
PublicKey pub = new PublicKey(_pubKey);
_hash160 = pub.Hash160;
return true;
}
return false;
}
protected byte _addressType = 0;
/// <summary>
/// Returns true if it is possible to return or calculate the Address.
/// </summary>
public virtual bool IsAddressAvailable() {
// Return true on having the address if we have hash160, pubkey, or privkey (since all can be used
// to calculate the address). Avoid actually calculating it because it's expensive.
if (_hash160 != null) return true;
if (_pubKey != null) return true;
if (_privKey != null) return true;
return false;
}
/// <summary>
/// Gets address if known or can be calculated.
/// Throws an InvalidOperationException if not.
/// </summary>
public AddressBase GetAddress() {
if (_hash160 == null) {
calculateHash160();
if (IsAddressAvailable() == false) {
throw new InvalidOperationException("Address is not available");
}
}
return new AddressBase(_hash160, _addressType);
}
}
}