从零开始的java区块链之路(二) 区块链钱包设计。

一个 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

posted @ 2019-12-15 14:23  caomaoboy  阅读(933)  评论(0)    收藏  举报