密码学技术在区块链系统中的应用

爱⌒轻易说出口 提交于 2019-11-26 03:22:56

密码学技术是区块链数据核心技术(P2P网络协议、共识机制、密码学技术、账户与存储模型)中核心的技术点,区块链主要用到的密码算法有哈希算法和加密算法,加密又包括对称性加密和非对称性加密两个概念,区块链系统里面一般常用到的是非对称加密。

本文首先把密码学相关的知识说明一下,并附有部分JAVA代码,然后用比特币作为例子说明一下在区块链系统中的使用。

【算法说明】

(一)哈希算法

哈希算法是区块链中用的最多的一种算法,它被广泛的使用在构建区块和确认交易的完整性上。

它是一类数学函数算法,又被称为散列算法,需具备三个基本特性:

1、其输入可为任意大小的字符串
2、它产生固定大小的输出
3、它能进行有效计算,也就是能在合理的时间内就能算出输出值
如果要求哈希算法达到密码学安全的话,我们还要求它具备以下三个附加特性:

1、碰撞阻力:
是指对于两个不同的输入,必须产生两个不同的输出。如果对于两个不同的输入产生了相同的输出,那么就说明不具备碰撞阻力,或是弱碰撞阻力。
2、隐秘性:
也被称为不可逆性,是指 y = HASH(x)中,通过输入值x,可以计算出输出值y,但是无法通过y值去反推计算出x值。为了保证不可逆,就得让x的取值来自一个非常广泛的集合,使之很难通过计算反推出x值。
3、谜题友好:
这个特性可以理解为,谜题是公平友好的,例如算法中 y = HASH(x),如果已知y值,想去得到x值,那就必须暴力枚举,不断的尝试才能做到,并且没有比这更好的办法,没有捷径。
哈希算法有很多,比特币主要使用的哈希算法是 SHA-256 算法。

除此之外,还有其他一些哈希算法也很流行,例如 MD5、SHA-1、SHA-2(SHA-224、SHA-256、SHA-384、SHA-512)、SHA-3 等,其中 MD5、SHA-1 已被证明了不具备 强碰撞阻力,安全性不够高,因此市场上不再推荐使用。

Java 代码(略)

(二)对称加密(Symmetric Cryptography)

对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)。对称加密有很多种算法,由于它效率很高,所以被广泛使用在很多加密协议的核心当中。

对称加密通常使用的是相对较小的密钥,一般小于256 bit。因为密钥越大,加密越强,但加密与解密的过程越慢。如果你只用1 bit来做这个密钥,那们可以先试着用0来解密,不行的话就再用1解;但如果你的密钥有1 MB大,们可能永远也无法破解,但加密和解密的过程要花费很长的时间。密钥的大小既要照顾到安全性,也要照顾到效率,是一个trade-off。

所谓对称加密算法即:加密和解密使用相同密钥的算法。常见的有DES、3DES、AES、PBE等加密算法,这几种算法安全性依次是逐渐增强的。

DES加密

DES是一种对称加密算法,是一种非常简便的加密算法,但是密钥长度比较短。DES加密算法出自IBM的研究,后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,24小时内即可被破解。

虽然如此,在某些简单应用中,我们还是可以使用DES加密算法.

简单的DES加密算法JAVA实现:

public class DESUtil {

private static final String KEY_ALGORITHM = "DES";
private static final String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";//默认的加密算法

/**
 * DES 加密操作
 *
 * @param content 待加密内容
 * @param key 加密密钥
 * @return 返回Base64转码后的加密数据
 */
public static String encrypt(String content, String key) {
    try {
        Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 创建密码器

        byte[] byteContent = content.getBytes("utf-8");

        cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key));// 初始化为加密模式的密码器

        byte[] result = cipher.doFinal(byteContent);// 加密

        return Base64.encodeBase64String(result);//通过Base64转码返回
    } catch (Exception ex) {
        Logger.getLogger(DESUtil.class.getName()).log(Level.SEVERE, null, ex);
    }

    return null;
}

/**
 * DES 解密操作
 *
 * @param content
 * @param key
 * @return
 */
public static String decrypt(String content, String key) {

    try {
        //实例化
        Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);

        //使用密钥初始化,设置为解密模式
        cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key));

        //执行操作
        byte[] result = cipher.doFinal(Base64.decodeBase64(content));

        return new String(result, "utf-8");
    } catch (Exception ex) {
        Logger.getLogger(DESUtil.class.getName()).log(Level.SEVERE, null, ex);
    }

    return null;
}

/**
 * 生成加密秘钥
 *
 * @return
 */
private static SecretKeySpec getSecretKey(final String key) {
    //返回生成指定算法密钥生成器的 KeyGenerator 对象
    KeyGenerator kg = null;

    try {
        kg = KeyGenerator.getInstance(KEY_ALGORITHM);

        //DES 要求密钥长度为 56
        kg.init(56, new SecureRandom(key.getBytes()));

        //生成一个密钥
        SecretKey secretKey = kg.generateKey();

        return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为DES专用密钥
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(DESUtil.class.getName()).log(Level.SEVERE, null, ex);
    }

    return null;
}

public static void main(String[] args) {
    String content = "hello,您好";
    String key = "sde@5f98H*^hsff%dfs$r344&df8543*er";
    System.out.println("content:" + content);
    String s1 = DESUtil.encrypt(content, key);
    System.out.println("s1:" + s1);
    System.out.println("s2:"+ DESUtil.decrypt(s1, key));

}

}

3DES加密

3DES是一种对称加密算法,在 DES 的基础上,使用三重数据加密算法,对数据进行加密,它相当于是对每个数据块应用三次 DES 加密算法。由于计算机运算能力的增强,原版 DES 密码的密钥长度变得容易被暴力破解;3DES 即是设计用来提供一种相对简单的方法,即通过增加 DES 的密钥长度来避免类似的***,而不是设计一种全新的块密码算法这样来说,破解的概率就小了很多。缺点由于使用了三重数据加密算法,可能会比较耗性能。简单的3DES加密算法实现:
(略)

(三)非对称加密

非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。一般公钥是公开的,私钥是自己保存。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。安全性相对对称加密来说更高,是一种高级加密方式。

RSA加密

RSA是一种非对称加密算法.RSA有两个密钥,一个是公开的,称为公开密钥;一个是私密的,称为私密密钥。公开密钥是对大众公开的,私密密钥是服务器私有的,两者不能互推得出。用公开密钥对数据进行加密,私密密钥可解密;私密密钥对数据加密,公开密钥可解密。速度较对称加密慢。

简单的RSA加密算法JAVA实现:

/**

  • <p>
  • RSA公钥/私钥/签名工具包
  • </p>
  • <p>
  • 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/>
  • 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/>
  • 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的效率和安全
  • </p>
  • */
    public class RSAUtils {

    /**

    • 加密算法RSA
      */
      public static final String KEY_ALGORITHM = "RSA";

    /**

    • 签名算法
      */
      public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    /**

    • 获取公钥的key
      */
      private static final String PUBLIC_KEY = "RSAPublicKey";

    /**

    • 获取私钥的key
      */
      private static final String PRIVATE_KEY = "RSAPrivateKey";

    /**

    • RSA最大加密明文大小
      */
      private static final int MAX_ENCRYPT_BLOCK = 117;

    /**

    • RSA最大解密密文大小
      */
      private static final int MAX_DECRYPT_BLOCK = 128;

    /**

    • <p>
    • 生成密钥对(公钥和私钥)
    • </p>
    • @return
    • @throws Exception
      */
      public static Map<String, Object> genKeyPair() throws Exception {
      KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
      keyPairGen.initialize(1024);
      KeyPair keyPair = keyPairGen.generateKeyPair();
      RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
      RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
      Map<String, Object> keyMap = new HashMap<String, Object>(2);
      keyMap.put(PUBLIC_KEY, publicKey);
      keyMap.put(PRIVATE_KEY, privateKey);
      return keyMap;
      }

    /**

    • <p>
    • 用私钥对信息生成数字签名
    • </p>
    • @param data 已加密数据
    • @param privateKey 私钥(BASE64编码)
    • @return
    • @throws Exception
      */
      public static String sign(byte[] data, String privateKey) throws Exception {
      byte[] keyBytes = Base64Utils.decode(privateKey);
      PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
      PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
      Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
      signature.initSign(privateK);
      signature.update(data);
      return Base64Utils.encode(signature.sign());
      }

    /**

    • <p>
    • 校验数字签名
    • </p>
    • @param data 已加密数据
    • @param publicKey 公钥(BASE64编码)
    • @param sign 数字签名
    • @return
    • @throws Exception
    • */
      public static boolean verify(byte[] data, String publicKey, String sign)
      throws Exception {
      byte[] keyBytes = Base64Utils.decode(publicKey);
      X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
      PublicKey publicK = keyFactory.generatePublic(keySpec);
      Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
      signature.initVerify(publicK);
      signature.update(data);
      return signature.verify(Base64Utils.decode(sign));
      }

    /**

    • <P>
    • 私钥解密
    • </p>
    • @param encryptedData 已加密数据
    • @param privateKey 私钥(BASE64编码)
    • @return
    • @throws Exception
      /
      public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)
      throws Exception {
      byte[] keyBytes = Base64Utils.decode(privateKey);
      PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
      Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
      Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
      cipher.init(Cipher.DECRYPT_MODE, privateK);
      int inputLen = encryptedData.length;
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      int offSet = 0;
      byte[] cache;
      int i = 0;
      // 对数据分段解密
      while (inputLen - offSet > 0) {
      if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
      cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
      } else {
      cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
      }
      out.write(cache, 0, cache.length);
      i++;
      offSet = i
      MAX_DECRYPT_BLOCK;
      }
      byte[] decryptedData = out.toByteArray();
      out.close();
      return decryptedData;
      }

    /**

    • <p>
    • 公钥解密
    • </p>
    • @param encryptedData 已加密数据
    • @param publicKey 公钥(BASE64编码)
    • @return
    • @throws Exception
      /
      public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)
      throws Exception {
      byte[] keyBytes = Base64Utils.decode(publicKey);
      X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
      Key publicK = keyFactory.generatePublic(x509KeySpec);
      Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
      cipher.init(Cipher.DECRYPT_MODE, publicK);
      int inputLen = encryptedData.length;
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      int offSet = 0;
      byte[] cache;
      int i = 0;
      // 对数据分段解密
      while (inputLen - offSet > 0) {
      if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
      cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
      } else {
      cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
      }
      out.write(cache, 0, cache.length);
      i++;
      offSet = i
      MAX_DECRYPT_BLOCK;
      }
      byte[] decryptedData = out.toByteArray();
      out.close();
      return decryptedData;
      }

    /**

    • <p>
    • 公钥加密
    • </p>
    • @param data 源数据
    • @param publicKey 公钥(BASE64编码)
    • @return
    • @throws Exception
      /
      public static byte[] encryptByPublicKey(byte[] data, String publicKey)
      throws Exception {
      byte[] keyBytes = Base64Utils.decode(publicKey);
      X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
      Key publicK = keyFactory.generatePublic(x509KeySpec);
      // 对数据加密
      Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
      cipher.init(Cipher.ENCRYPT_MODE, publicK);
      int inputLen = data.length;
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      int offSet = 0;
      byte[] cache;
      int i = 0;
      // 对数据分段加密
      while (inputLen - offSet > 0) {
      if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
      cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
      } else {
      cache = cipher.doFinal(data, offSet, inputLen - offSet);
      }
      out.write(cache, 0, cache.length);
      i++;
      offSet = i
      MAX_ENCRYPT_BLOCK;
      }
      byte[] encryptedData = out.toByteArray();
      out.close();
      return encryptedData;
      }

    /**

    • <p>
    • 私钥加密
    • </p>
    • @param data 源数据
    • @param privateKey 私钥(BASE64编码)
    • @return
    • @throws Exception
      /
      public static byte[] encryptByPrivateKey(byte[] data, String privateKey)
      throws Exception {
      byte[] keyBytes = Base64Utils.decode(privateKey);
      PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
      Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
      Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
      cipher.init(Cipher.ENCRYPT_MODE, privateK);
      int inputLen = data.length;
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      int offSet = 0;
      byte[] cache;
      int i = 0;
      // 对数据分段加密
      while (inputLen - offSet > 0) {
      if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
      cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
      } else {
      cache = cipher.doFinal(data, offSet, inputLen - offSet);
      }
      out.write(cache, 0, cache.length);
      i++;
      offSet = i
      MAX_ENCRYPT_BLOCK;
      }
      byte[] encryptedData = out.toByteArray();
      out.close();
      return encryptedData;
      }

    /**

    • <p>
    • 获取私钥
    • </p>
    • @param keyMap 密钥对
    • @return
    • @throws Exception
      */
      public static String getPrivateKey(Map<String, Object> keyMap)
      throws Exception {
      Key key = (Key) keyMap.get(PRIVATE_KEY);
      return Base64Utils.encode(key.getEncoded());
      }

    /**

    • <p>
    • 获取公钥
    • </p>
    • @param keyMap 密钥对
    • @return
    • @throws Exception
      */
      public static String getPublicKey(Map<String, Object> keyMap)
      throws Exception {
      Key key = (Key) keyMap.get(PUBLIC_KEY);
      return Base64Utils.encode(key.getEncoded());
      }

}

/**

  • <p>
  • RSA公钥/私钥/签名工具包
  • </p>
  • <p>
  • 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式<br/>
  • 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,<br/>
  • 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全
  • </p>
  • */
    public class RSAUtils {

    /**

    • 加密算法RSA
      */
      public static final String KEY_ALGORITHM = "RSA";

    /**

    • 签名算法
      */
      public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    /**

    • 获取公钥的key
      */
      private static final String PUBLIC_KEY = "RSAPublicKey";

    /**

    • 获取私钥的key
      */
      private static final String PRIVATE_KEY = "RSAPrivateKey";

    /**

    • RSA最大加密明文大小
      */
      private static final int MAX_ENCRYPT_BLOCK = 117;

    /**

    • RSA最大解密密文大小
      */
      private static final int MAX_DECRYPT_BLOCK = 128;

    /**

    • <p>
    • 生成密钥对(公钥和私钥)
    • </p>
    • @return
    • @throws Exception
      */
      public static Map<String, Object> genKeyPair() throws Exception {
      KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
      keyPairGen.initialize(1024);
      KeyPair keyPair = keyPairGen.generateKeyPair();
      RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
      RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
      Map<String, Object> keyMap = new HashMap<String, Object>(2);
      keyMap.put(PUBLIC_KEY, publicKey);
      keyMap.put(PRIVATE_KEY, privateKey);
      return keyMap;
      }

    /**

    • <p>
    • 用私钥对信息生成数字签名
    • </p>
    • @param data 已加密数据
    • @param privateKey 私钥(BASE64编码)
    • @return
    • @throws Exception
      */
      public static String sign(byte[] data, String privateKey) throws Exception {
      byte[] keyBytes = Base64Utils.decode(privateKey);
      PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
      PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
      Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
      signature.initSign(privateK);
      signature.update(data);
      return Base64Utils.encode(signature.sign());
      }

    /**

    • <p>
    • 校验数字签名
    • </p>
    • @param data 已加密数据
    • @param publicKey 公钥(BASE64编码)
    • @param sign 数字签名
    • @return
    • @throws Exception
    • */
      public static boolean verify(byte[] data, String publicKey, String sign)
      throws Exception {
      byte[] keyBytes = Base64Utils.decode(publicKey);
      X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
      PublicKey publicK = keyFactory.generatePublic(keySpec);
      Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
      signature.initVerify(publicK);
      signature.update(data);
      return signature.verify(Base64Utils.decode(sign));
      }

    /**

    • <P>
    • 私钥解密
    • </p>
    • @param encryptedData 已加密数据
    • @param privateKey 私钥(BASE64编码)
    • @return
    • @throws Exception
      /
      public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)
      throws Exception {
      byte[] keyBytes = Base64Utils.decode(privateKey);
      PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
      Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
      Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
      cipher.init(Cipher.DECRYPT_MODE, privateK);
      int inputLen = encryptedData.length;
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      int offSet = 0;
      byte[] cache;
      int i = 0;
      // 对数据分段解密
      while (inputLen - offSet > 0) {
      if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
      cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
      } else {
      cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
      }
      out.write(cache, 0, cache.length);
      i++;
      offSet = i
      MAX_DECRYPT_BLOCK;
      }
      byte[] decryptedData = out.toByteArray();
      out.close();
      return decryptedData;
      }

    /**

    • <p>
    • 公钥解密
    • </p>
    • @param encryptedData 已加密数据
    • @param publicKey 公钥(BASE64编码)
    • @return
    • @throws Exception
      /
      public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)
      throws Exception {
      byte[] keyBytes = Base64Utils.decode(publicKey);
      X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
      Key publicK = keyFactory.generatePublic(x509KeySpec);
      Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
      cipher.init(Cipher.DECRYPT_MODE, publicK);
      int inputLen = encryptedData.length;
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      int offSet = 0;
      byte[] cache;
      int i = 0;
      // 对数据分段解密
      while (inputLen - offSet > 0) {
      if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
      cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
      } else {
      cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
      }
      out.write(cache, 0, cache.length);
      i++;
      offSet = i
      MAX_DECRYPT_BLOCK;
      }
      byte[] decryptedData = out.toByteArray();
      out.close();
      return decryptedData;
      }

    /**

    • <p>
    • 公钥加密
    • </p>
    • @param data 源数据
    • @param publicKey 公钥(BASE64编码)
    • @return
    • @throws Exception
      /
      public static byte[] encryptByPublicKey(byte[] data, String publicKey)
      throws Exception {
      byte[] keyBytes = Base64Utils.decode(publicKey);
      X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
      Key publicK = keyFactory.generatePublic(x509KeySpec);
      // 对数据加密
      Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
      cipher.init(Cipher.ENCRYPT_MODE, publicK);
      int inputLen = data.length;
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      int offSet = 0;
      byte[] cache;
      int i = 0;
      // 对数据分段加密
      while (inputLen - offSet > 0) {
      if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
      cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
      } else {
      cache = cipher.doFinal(data, offSet, inputLen - offSet);
      }
      out.write(cache, 0, cache.length);
      i++;
      offSet = i
      MAX_ENCRYPT_BLOCK;
      }
      byte[] encryptedData = out.toByteArray();
      out.close();
      return encryptedData;
      }

    /**

    • <p>
    • 私钥加密
    • </p>
    • @param data 源数据
    • @param privateKey 私钥(BASE64编码)
    • @return
    • @throws Exception
      /
      public static byte[] encryptByPrivateKey(byte[] data, String privateKey)
      throws Exception {
      byte[] keyBytes = Base64Utils.decode(privateKey);
      PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
      Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
      Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
      cipher.init(Cipher.ENCRYPT_MODE, privateK);
      int inputLen = data.length;
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      int offSet = 0;
      byte[] cache;
      int i = 0;
      // 对数据分段加密
      while (inputLen - offSet > 0) {
      if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
      cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
      } else {
      cache = cipher.doFinal(data, offSet, inputLen - offSet);
      }
      out.write(cache, 0, cache.length);
      i++;
      offSet = i
      MAX_ENCRYPT_BLOCK;
      }
      byte[] encryptedData = out.toByteArray();
      out.close();
      return encryptedData;
      }

    /**

    • <p>
    • 获取私钥
    • </p>
    • @param keyMap 密钥对
    • @return
    • @throws Exception
      */
      public static String getPrivateKey(Map<String, Object> keyMap)
      throws Exception {
      Key key = (Key) keyMap.get(PRIVATE_KEY);
      return Base64Utils.encode(key.getEncoded());
      }

    /**

    • <p>
    • 获取公钥
    • </p>
    • @param keyMap 密钥对
    • @return
    • @throws Exception
      */
      public static String getPublicKey(Map<String, Object> keyMap)
      throws Exception {
      Key key = (Key) keyMap.get(PUBLIC_KEY);
      return Base64Utils.encode(key.getEncoded());
      }

}

public class Base64Utils {

/**
 * 文件读取缓冲区大小
 */
private static final int CACHE_SIZE = 1024;

/**
 * <p>
 * BASE64字符串解码为二进制数据
 * </p>
 *
 * @param base64
 * @return
 * @throws Exception
 */
public static byte[] decode(String base64) throws Exception {
    return Base64.decode(base64.getBytes());
}

/**
 * <p>
 * 二进制数据编码为BASE64字符串
 * </p>
 *
 * @param bytes
 * @return
 * @throws Exception
 */
public static String encode(byte[] bytes) throws Exception {
    return new String(Base64.encode(bytes));
}

/**
 * <p>
 * 将文件编码为BASE64字符串
 * </p>
 * <p>
 * 大文件慎用,可能会导致内存溢出
 * </p>
 *
 * @param filePath
 *            文件绝对路径
 * @return
 * @throws Exception
 */
public static String encodeFile(String filePath) throws Exception {
    byte[] bytes = fileToByte(filePath);
    return encode(bytes);
}

/**
 * <p>
 * BASE64字符串转回文件
 * </p>
 *
 * @param filePath
 *            文件绝对路径
 * @param base64
 *            编码字符串
 * @throws Exception
 */
public static void decodeToFile(String filePath, String base64) throws Exception {
    byte[] bytes = decode(base64);
    byteArrayToFile(bytes, filePath);
}

/**
 * <p>
 * 文件转换为二进制数组
 * </p>
 *
 * @param filePath
 *            文件路径
 * @return
 * @throws Exception
 */
public static byte[] fileToByte(String filePath) throws Exception {
    byte[] data = new byte[0];
    File file = new File(filePath);
    if (file.exists()) {
        FileInputStream in = new FileInputStream(file);
        ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
        byte[] cache = new byte[CACHE_SIZE];
        int nRead = 0;
        while ((nRead = in.read(cache)) != -1) {
            out.write(cache, 0, nRead);
            out.flush();
        }
        out.close();
        in.close();
        data = out.toByteArray();
    }
    return data;
}

/**
 * <p>
 * 二进制数据写文件
 * </p>
 *
 * @param bytes
 *            二进制数据
 * @param filePath
 *            文件生成目录
 */
public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception {
    InputStream in = new ByteArrayInputStream(bytes);
    File destFile = new File(filePath);
    if (!destFile.getParentFile().exists()) {
        destFile.getParentFile().mkdirs();
    }
    destFile.createNewFile();
    OutputStream out = new FileOutputStream(destFile);
    byte[] cache = new byte[CACHE_SIZE];
    int nRead = 0;
    while ((nRead = in.read(cache)) != -1) {
        out.write(cache, 0, nRead);
        out.flush();
    }
    out.close();
    in.close();
}

}

【密码技术在区块链中的使用(比特币为例)】

一、区块链中的哈希算法

我们以比特币为例,来看一下哈希算法的具体应用:
在比特币中,使用哈希算法把交易生成数据摘要,当前区块里面包含上一个区块的哈希值,后面一个区块又包含当前区块的哈希值,就这样一个接一个的连接起来,形成一个哈希指针链表,如下图:

密码学技术在区块链系统中的应用

上面只是示意图,那么在实际比特币系统中,每个区块包含哪些内容呢:

密码学技术在区块链系统中的应用

重点关注一下上图中的:

Prev Block:记录签一个区块的hash地址,32字节
Merkle Root:是一个记录当前块内的所有交易信息的数据摘要hash值,32字节
Nonce:一个随机值,需要通过这个随机值去找到满足某个条件的hash值(挖矿),4字节
上面只是解释了几个重点的字段,其它字段通过字面应该容易理解就不一一解释了。
这所有的字段一起就组成了 block header(区块头),然后需要对 block header 进行2次hash计算,计算完成的值就是当前比特币区块的hash值。因为比特币系统要求计算出来的这个hash值满足一定的条件(小于某个数值),因此需要我们不断的遍历Nonce值去计算新的hash值以满足要求,只有找到了满足要求的hash值,那么这就是一个合法区块了(这一系列动作也叫作挖矿)

示例:
SHA-256(SHA-256 (Block Header)
我们再看一下上面的另一个重要字段: Merkle tree 字段。
Merkle tree 被称为 默克尔树,它也是哈希算法的一个重要应用。
它其实是一个用哈希指针建立的二叉树或多叉树。

Merkle tree 如图:

密码学技术在区块链系统中的应用

其树的顶端叫做 默克尔根(Merkle Root),Merkle Root 也是一个hash值,它是怎么计算出来的呢?

比特币中对每一笔交易做一个hash计算,然后把每2个交易的hash再进行合并做hash,如图中的 交易A的hash值是 H(A),交易B的hash值是H(B),再对这2个交易合并hash后就是H(hA|hb),就这样一直往上合并计算,算到最后的根部就是 Merkle Root 了。

在比特币和以太坊中都是使用的默克尔树结构,但是以太坊为了实现更多复杂的功能,所以有三个默克尔树。

至此,区块链中的哈希算法应用就介绍完了,接下来我们看一下非对称加密算法。

二、区块链中的非对称加密算法

区块链中有一个很关键的点就是账户问题,但比特币中是没有账户概念的,那大家是怎么进行转账交易的呢?

这里就得先介绍区块链中的非对称加密技术了。

非对称加密技术有很多种,如:RSA、ECC、ECDSA 等,比特币中是使用的 ECDSA 算法。
ECDSA 是美国政府的标准,是利用了椭圆曲线的升级版,这个算法经过了数年的细致密码分析,被广泛认为是安全可靠的。

所谓非对称加密是指我们在对数据进行加密和解密的时候,需使用2个不同的密钥。比如,我们可以用A密钥将数据进行加密,然后用B密钥来解密,相反,也可以用B来加密,然后使用A来解密。那么如果我想给某个人传递信息,那我可以先用A加密后,将密文传给她,她拿到密文之后,用手上的B密钥去解开。这2个密钥,一个被成为公钥、一个是私钥。

在比特币中,每个用户都有一对密钥(公钥和私钥),比特币系统中是使用用户的公钥作为交易账户的。
我们先看下图:

密码学技术在区块链系统中的应用

在图中可以看到,在第一笔交易记录中,是 用户U0 来发起的交易,要将代币支付给 用户U1,是怎么实现的呢?

1、首先 用户U0 写好交易信息:data(明文,例如:用户U0转账100元给用户U1),并用U1的公钥加密;

2、用户U0 使用哈希算法将加密交易信息进行计算,得出 H = hash(data),然后再使用自己的私钥对 H 进行签名,即 S(H),这一步其实是为了防止交易信息网络传输中被篡改用的;

3、然后基于区块链网络,将 签名S(H) 和 加密交易信息data 传递给 用户U1;

4、用户U1 使用 用户U0 的公钥 来对 S(H) 解密,就得到了加密交易信息的哈希值 H,同时,用户U1 还使用哈希算法对 加密交易信息data 进行计算,得出 H2 = hash(data);

5、对比上面2个哈希值,如果 H1==H2,则数据未被篡改且交易合法。说明 用户U0 在发起交易的时候确实拥有真实的私钥,有权发起自己账户的交易;

6、网络中每一个节点都可以参与上述的验证步骤。

这个示例,就是比特币中一次交易的签名流程,即将 哈希算法与非对称算法结合在一起用于了比特币交易的数字签名。 除此之外,比特币中,公私钥的生成、比特币地址的生成也是由非对称加密算法来保证的。

以上,就是区块链体系中,核心技术之哈希算法与加密算法的应用情况。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!