一个 Bitcoin 钱包包含了一系列的密钥对,每个密钥对都是由一对公钥(public key)和私钥(private key)组成。私钥(k)通常是随机选出的一串数字串,之后我们就可以通过椭圆曲线密码学(ECC)算法来产生一个公钥(K),然后再通过单向的 Hash 算法来生成 Bitcoin 地址。
非对称加密算法-RSA
- 唯一广泛接受并实现
- 数据加密&数字签名
- 公钥加密、私钥解密
- 私钥加密、公钥解密
- RSA相对比较慢
- 基于“大数因子分解”非对称加密算法的实现方式
JDK实现
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import org.apache.commons.codec.binary.Base64;
import com.sun.org.apache.xalan.internal.utils.Objects;
public class RSATest {
public static final String src = "rsa test";
public static void main(String[] args) {
jdkRSA();
}
// jdk实现:
public static void jdkRSA(){
try {
// 1.初始化发送方密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
System.out.println("Public Key:" + Base64.encodeBase64String(rsaPublicKey.getEncoded()));
System.out.println("Private Key:" + Base64.encodeBase64String(rsaPrivateKey.getEncoded()));
// 2.私钥加密、公钥解密 ---- 加密
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("私钥加密、公钥解密 ---- 加密:" + Base64.encodeBase64String(result));
// 3.私钥加密、公钥解密 ---- 解密
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
result = cipher.doFinal(result);
System.out.println("私钥加密、公钥解密 ---- 解密:" + new String(result));
// 4.公钥加密、私钥解密 ---- 加密
X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
KeyFactory keyFactory2 = KeyFactory.getInstance("RSA");
PublicKey publicKey2 = keyFactory2.generatePublic(x509EncodedKeySpec2);
Cipher cipher2 = Cipher.getInstance("RSA");
cipher2.init(Cipher.ENCRYPT_MODE, publicKey2);
byte[] result2 = cipher2.doFinal(src.getBytes());
System.out.println("公钥加密、私钥解密 ---- 加密:" + Base64.encodeBase64String(result2));
// 5.私钥解密、公钥加密 ---- 解密
PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory5 = KeyFactory.getInstance("RSA");
PrivateKey privateKey5 = keyFactory5.generatePrivate(pkcs8EncodedKeySpec5);
Cipher cipher5 = Cipher.getInstance("RSA");
cipher5.init(Cipher.DECRYPT_MODE, privateKey5);
byte[] result5 = cipher5.doFinal(result2);
System.out.println("公钥加密、私钥解密 ---- 解密:" + new String(result5));
} catch (Exception e) {
e.printStackTrace();
}
}
}
描述:
地址是为了人们交换方便而弄出来的一个方案,因为公钥太长了(130字符串或66字符串)。地址长度为25字节,转为base58编码后,为34或35个字符。base58是类似base64的编码,但去掉了易引起视觉混淆的字符,又在地址末尾添加了4个字节校验位,保障在人们交换个别字符错误时,也能够因地址校验失败而制止了误操作。
由于存在公钥有两种形式,那么一个公钥便对应两个地址。这两个地址都可由同一私钥签署交易。
密钥类型
存在三种密钥,并且都是使用 Base58Check 编码成 ASCII 码呈现:
- 私钥 (private key)
- 公钥 (public key)
- 地址 (address)
- 比特币地址生成的过程
如何生成地址(公钥哈希 hash of public key)
简单钱包的结构
钱包的结构其实很简单的 就是账号密码 重点是 由于RSA生成的账号比较长不利于记忆 需要一系列的 加密 使地址变短。 至于为什么么没有 余额 余额其实是通过每笔交易 也就是每个区块 去计算出来的 并不是钱包里 固定的一个数值。
public class Wallet {
/**
*
* @return 获取钱包地址
*/
public String getAddress() throws NoSuchAlgorithmException {
return WalletUtils.generateAddressWithBase58Check(publicKey.getBytes());
}
//钱包的私钥和秘钥生成之后就不用再改了 所以 不需要set
public String getPrivateKey() {
return privateKey;
}
//公钥 相当于账号
private String publicKey;
//私钥 相当于密码
private String privateKey;
public Wallet(String publicKey,String privateKey){
this.privateKey =privateKey;
this.publicKey = publicKey;
}
//生成钱包地址 钱包地址 不用公钥是为了方便记忆
public static Wallet generateWallet() throws Exception {
KeyPair keyPair = RSACoder.getKeyPair(1024);
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String publickey = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
String privatekey = new String(Base64.getEncoder().encode(privateKey.getEncoded()));
return new Wallet(publickey,privatekey);
}
最后生成的钱包地址1C2zCwTWpnmkNJ4mK9dNBsRVY74j53aVPM