Java语言实现区块链(四)

一、签名和校验

比特币通过对交易进行签名和校验,保证交易的安全性。

下图展示了数据签名和交易的过程。

签名过程:

1)使用哈希算法对数据文件进行加密处理,得到一个哈希值;

2)使用私钥对哈希值进行加密,生成数字签名;

3)最后把数据文件和数字签名一起发送给对方;

 

校验过程:

1)对方接收到数据文件和数字签名之后,首先使用相同的哈希算法对数据文件进行加密处理,得到一个哈希值;

2)使用公钥对数字签名进行解密,得到解密后的哈希;

3)将1和2得到的哈希值进行比较,如果相等代表验证通过;

二、添加交易功能

(1)定义和初始化钱包

// 钱包
public class Wallet {
    // 钱包私钥
    public PrivateKey privateKey;
    // 钱包公钥
    public PublicKey publicKey;
    // 用户名字,创建钱包时候传入
    private String name;

    public Wallet(String name) {
        this.name = name;
        // 判断私钥和公钥是否存在,如果不存在,则创建它们
        File priKeyFile = new File(name + ".pri");
        File pubKeyFile = new File(name + ".pub");
        if (!priKeyFile.exists() || priKeyFile.length() == 0
                || !pubKeyFile.exists() || pubKeyFile.length() == 0) {
            RSAUtils.generateKeysJS("RSA", name + ".pri", name + ".pub");
        }
    }
}

(2)定义交易

// 交易
public class Transaction {
    // 付款方公钥
    public String senderPublicKey;
    // 收款方公钥
    public String receiverPublicKey;
    // 金额
    public String content;
    // 签名
    public String signaturedData;

    public Transaction() {
    }

    public Transaction(String senderPublicKey, String receiverPublicKey, String content, String signaturedData) {
        this.senderPublicKey = senderPublicKey;
        this.receiverPublicKey = receiverPublicKey;
        this.content = content;
        this.signaturedData = signaturedData;
    }

    ...
}

(3)在Wallet中提供创建交易的方法。 

// 转账
// 参数一:接收方的公钥
// 参数二:交易数据
public Transaction sendMoney(String receiverPublicKey, String content) {
    // 生成签名
    String signature = RSAUtils.getSignature("SHA256withRSA", privateKey, content);
    // 把publicKey对象转换成字符串
    String senderPublicKey = Base64.encode(publicKey.getEncoded());
    // 创建并返回交易
    return new Transaction(senderPublicKey, receiverPublicKey, content, signature);
}

(4)在Transaction中定义校验交易的方法。

// 校验交易的方法
public boolean verify() {
    PublicKey publicKey = RSAUtils.getPublicKeyFromString("RSA", senderPublicKey);
    return RSAUtils.verifyDataJS("SHA256withRSA", publicKey, content, signaturedData);
}

(5)在客户端生成私钥。

第一步:添加发送方的私钥和公钥(数字签名和认证),以及接收方公钥(对方钱包地址)的输入框;

<label>发送方私钥oc
    </label>
    <textarea class="form-control" id="senderPrivateKey">-----BEGIN PRIVATE KEY-----
    MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCX/Nt0pTfSdSH6GRW/tJOeEqTo
    2ExsUPakhTMhPHJOQjLPwaHHqkBnmHBGYr8fsu8wqmTb0Uy3yccJ2InqB3If7yYFwiihI5Gjtwjr
    13oMUJqma8tAULEGrIIj081LRIBGCSbTohb0qqVPIQkP8rI11Jjx8UYAhon2xl1DrcVGzJnCMJ0D
    H0ovq4gJboIwKxij4SJKEDiwKDqvFc4VKLI9KUJq5y3FjZMPAsKRC0e2psJCI7i+HhF4kq8usnkm
    6z993emwV24JP1dpe8CeYrAgrLApZ5yEmEZv557YstNVwOhWCYFl9GkGTh1UU9eC3DTcKW+hzZtW
    fhKhtNRJyfzHAgMBAAECggEAcPKhJ/MsI8OWR2Ti679HQF58nOk5Cfm1ARhXoehozc2WMxyjnFzi
    VdpL/ZKek/EGnfTS1SSaTa6usptwCjIUVrUDXZ4nUXC8Z5y7DYDpG0O/WdObjSUqGVqTsApTcw7q
    AKIGb5nyU0qJZN+Y+3gRhb2DF7GEoxlYZ8KMRqJZi72VMEXHarCDILeiHlqzg66zNpE8L92pxKUE
    FzsbplK4XXeMdrgTZ2vdeISFyXn5Vd63UCv+6/N9ECSSpowEN1Q+3+v8Cb0+i5v22/qq5OYjFpOW
    KdSOI8umDZmNuNewN/vIhDR7GovjUhpyRDcUkL92AU4CK6ZUDGpydMJT+XC4OQKBgQDPTtb8f951
    fWC7YRJUrLfjACF57IEqCgJ4Dm0KLh4ZXK0uFk4ogtAf90ek9Rxu8fQ4411NOz7C71VUbhwOuLDr
    SaFdz/oNXecNBUWeYDQ82Xlm9Y6TGKe5bbzTZnPIUry98X/VWOkXMmQ7MIk8KliV21+0JJS2EeCe
    I0kOdLjDqwKBgQC7r67CrojOl7ZK66XFyw0IKmHoHoPTiiyht12Znj/gjoczxGx6Q7H9xjMghWkp
    ujtTrrTufT2XAId4WaTJsIjGC5GhkiINjoLZSnaNDeAcF7H1yDWyJgwNhmB/ROh4ehwAIblt/TT2
    DU28fYgBOFBInGb1M04Jx6ydc0H0ZO4PVQKBgQCKVk0GP/neIyVqxPMrh/pJw6uTJexndjiBjvba
    hT3WpM5347CSPgDOY//uJxarPlA/qhF32SIfiQBDEBsvA7YjvIWvCXsOcmwddzgm4IHbXTAzMYfL
    xvcduQn5c/OtaPDEO6SXZPZeYWUbTl81w/hLQBHUL1kBSlq+jENTHzawcwKBgFI8zGppZ3B+cVWq
    o1xjeDZXu8aleEW8iYniepTRDlQqn3tDWfTIrLjxm31od4fdHhmwt364ScBcbv+A5/+n5oZAk3Mk
    QN+HzjW/tupfZg9pIoT7UOvaV/WlJ6scWnBPsO0t2b4j8IzPj3xD1NAUCLmILmTKMit+3levJPsd
    LmJxAoGALeQADQ/HnicAQeWAJY4OPya5nHhthBflrSC9T100xHmh01pEWM/wsuHjSAoN1pFNfLs9
    vko+4B2omIcvzor4HsUJs5ZJhIP7A4vQDvd4k+3DBxMz8jvcm2x6aSpt8Mh4ZwGUo+Y/vCeCFLQv
    3BUGFh6UHw69Y0vmiGApQcpUY7g=
    -----END PRIVATE KEY-----</textarea>
    <label>发送方公钥
    </label>
    <textarea class="form-control" id="senderPublicKey">MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl/zbdKU30nUh+hkVv7STnhKk6NhMbFD2
    pIUzITxyTkIyz8Ghx6pAZ5hwRmK/H7LvMKpk29FMt8nHCdiJ6gdyH+8mBcIooSORo7cI69d6DFCa
    pmvLQFCxBqyCI9PNS0SARgkm06IW9KqlTyEJD/KyNdSY8fFGAIaJ9sZdQ63FRsyZwjCdAx9KL6uI
    CW6CMCsYo+EiShA4sCg6rxXOFSiyPSlCauctxY2TDwLCkQtHtqbCQiO4vh4ReJKvLrJ5Jus/fd3p
    sFduCT9XaXvAnmKwIKywKWechJhGb+ee2LLTVcDoVgmBZfRpBk4dVFPXgtw03Clvoc2bVn4SobTU
    Scn8xwIDAQAB</textarea>
    <label>接收方公钥
    </label>
    <textarea class="form-control" id="receiverPublicKey">MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1dpjVhAjVwz/yhi6lPoasRkmbk0zKU+T
    iP+2I35j3PUKXHawXRlN7/fqaiqM14WvYbgj2GzSHHT4b6WMIuH9Jbm7Vrqu0Daxszewx4RV9Ixg
    haurIx3e+7zAigavBRDidjlgSgmq9H7wwYL/hnVzPGf+oH09ymFkzXdtbrr0yZjwJ+Q3fT33Co5G
    ezbhNfL5ZVhOKoq+gdyTU9rhdoLXog1FVraz384rkPovVGi/TzvoGNNnie4qM1J5WzBKpJpmVwCo
    t7xLFC0fctTdR9iLpD6vNrlsetxHwceHSCLQSS/w3FR258g+mWZI1Kj6cqR6PL+qBDmpv7aRMm0N
    7e/3OwIDAQAB</textarea>

注意:赋值内容到textarea输入框时候,<textarea></textarea>标签之间不要有空格和换行。因为空格和换行都要导致哈希运算的结果不正确。

第二步:修改addBlock方法,在该方法中生成私钥,并发送给后台处理。

// 创建普通区块
function addBlock() {
    // 发送方私钥
    var senderPrivateKey = $("#senderPrivateKey").val();
    // 发送方公钥
    var senderPublicKey = $("#senderPublicKey").val();
    // 接收方公钥
    var receiverPublicKey = $("#receiverPublicKey").val();
    // 获取用户输入的内容
    var content = $("#content").val();
    //-------------------- 生成签名信息 -----------------
    // 获取私钥
    var prvKey = KEYUTIL.getKey(senderPrivateKey);
    // 指定算法
    var sig = new KJUR.crypto.Signature({"alg": "SHA256withRSA"});
    // 初始化私钥
    sig.init(prvKey);
    // 传入原文
    sig.updateString(content)
    // 生成签名
    var sigValueHex = sig.sign()
    console.log(sigValueHex);
    //----------------------------------------------------
    // 显示进度条
    loading.baosight.showPageLoadingMsg(false);
    // 发起请求
    $.post("addBlock", {
        senderPublicKey: senderPublicKey,
        receiverPublicKey: receiverPublicKey,
        content: content,
        signaturedData: sigValueHex
    }, function(data) {
        // 展示操作结果
        $("#result").html(data)
        // 展示最新数据
        showList();
        // 清空输入框
        $("#content").val("");
        // 隐藏进度条
        loading.baosight.hidePageLoadingMsg();
     });
}

(6)修改BlockController的addBlock方法,把方法参数改为Transaction对象,并且添加签名校验。

@RequestMapping(value = "/addBlock", method = RequestMethod.POST)
//public String addBlock(String content) {
public String addBlock(Transaction tx) {
    try {
        //noteBook.addBlock(content);
        //System.out.println(tx);
        if (tx.verify()) {
            // 把Transaction对象转换成字符串
            ObjectMapper objectMapper = new ObjectMapper();
            String txInfo = objectMapper.writeValueAsString(tx);
            // 执行添加操作
            noteBook.addBlock(txInfo);
            return "添加区块成功!";
         } else {
            throw new RuntimeException("交易数据校验失败!");
         }
     } catch (Exception e) {
         return "添加失败:" + e.getMessage();
     }
}

 

猜你喜欢

转载自blog.csdn.net/zhongliwen1981/article/details/89708079