Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

weileifrank/SignatureBaseOnJava

Repository files navigation

哈希算法

概念

称谓: 单向散列函数, 哈希函数, 杂凑函数, 消息摘要函数

接收的输入: 原像

输出: 散列值, 哈希值, 指纹, 摘要

单向散列函数特性

  1. 将任意长度的数据转换成固定长度的数据
  2. 很强的抗碰撞性
  3. 不可逆
  4. MD4/MD5
    • 不安全
    • 散列值长度: 128bit == 16byte
  5. sha1
    • 不安全
    • 散列值长度: 160bit == 20byte
  6. sha2 - 安全
    • sha224
      • 散列值长度: 224bit == 28byte
    • sha256
      • 散列值长度: 256== 32byte
    • sha384
      • 散列值长度: 384bit == 48byte
    • sha512
      • 散列值长度: 512bit == 64byte
  7. 示例代码如下
public class HashDemo {
 public static void main(String[] args) throws Exception {
 String input = "frank";
 String md5 = getDigest(input, "MD5");
 System.out.println("md5:"+md5);
 String sha1 = getDigest(input, "SHA-1");
 System.out.println("sha1:"+sha1);
 String sha256 = getDigest(input, "SHA-256");
 System.out.println("sha256:"+sha256);
 String sha512 = getDigest(input, "SHA-512");
 System.out.println("sha512:"+sha512);
 String fileSha1 = getDigestFile("a.txt", "SHA-1");
 System.out.println("fileSha1:"+fileSha1);
 }
 /**
 * 获取消息摘要
 *
 * @param input : 原文
 * @param algorithm : 算法
 * @return : 消息摘要
 * @throws Exception
 */
 public static String getDigest(String input, String algorithm) throws Exception {
 // 获取MessageDigest对象
 MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
 // 生成消息摘要
 byte[] digest = messageDigest.digest(input.getBytes());
 return toHex(digest);
 }
 /**
 * 
 * @param filePath 文件路径
 * @param algorithm 算法
 * @return 返回对应的哈希值
 * @throws Exception
 */
 public static String getDigestFile(String filePath, String algorithm) throws Exception {
 FileInputStream fis = new FileInputStream(filePath);
 int len;
 byte[] buffer = new byte[1024];
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 while ((len = fis.read(buffer)) != -1) {
 baos.write(buffer, 0, len);
 }
 // 获取MessageDigest对象
 MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
 // 生成消息摘要
 byte[] digest = messageDigest.digest(baos.toByteArray());
 return toHex(digest);
 }
 // 将字节数组转为16进制字符串
 public static String toHex(byte[] digest) {
 StringBuilder sb = new StringBuilder();
 for (byte b : digest) {
 int i = b & 0xff;
 String s = Integer.toHexString(i);
 if (s.length() == 1) {
 s = "0" + s;
 }
 sb.append(s);
 }
 return sb.toString();
 }
}

消息认证

消息认证码

消息认证码(message authentication code)是一种确认完整性并进行认证的技术,取三个单词的首字母,简称为MAC。

Logo

  • 思考改进方案?

    从哈希函数入手

    需要将要发送的数据进行哈希运算, 将哈希值和原始数据一并发送

    需要在进行哈希运算的时候引入加密的步骤

    • 在alice对数据进行哈希运算的时候引入一个秘钥, 让其参与哈希运算, 生成散列值
    • bob对数据校验
      • bob收到原始和散列值之后,
        • 处理原始数据: 通过秘钥和哈希算法对原始数据生成散列值
        • 散列值比较: 生成的散列值 和 接收到的散列值进行比对

消息认证码的使用步骤

Logo

  1. 前提条件:
    • 在消息认证码生成的一方和校验的一方, 必须有一个秘钥
    • 双方约定好使用同样的哈希函数对数据进行运算
  2. 流程:
    • 发送者:
      • 发送原始法消息
      • 将原始消息生成消息认证码
        • ((原始消息) + 秘钥) * 函数函数 = 散列值(消息认证码)
      • 将消息认证码发送给对方
    • 接收者:
      • 接收原始数据
      • 接收消息认证码
      • 校验:
        • ( 接收的消息 + 秘钥 ) * 哈希函数 = 新的散列值
        • 通过新的散列值和接收的散列值进行比较

消息认证码的问题

  1. 弊端
    • 有秘钥分发困难的问题
  2. 无法解决的问题
    • 不能进行第三方证明
    • 不能防止否认
  3. 消息认证码常见的算法如下: Logo
  4. 消息认证代码如下:
public class MacDemo {
 public static void main(String[] args) throws Exception {
 String input = "frank";
 String keyString = "123DLLFLH";
 String algorithm = "HmacSHA256";
 String hmac = generateHmac(input, keyString, algorithm);
 System.out.println(hmac);
 boolean b = verifyHamc("frank", keyString, algorithm, hmac);
 System.out.println(b);
 }
 /**
 *
 * @param input 原文
 * @param keyString 秘钥
 * @param algorithm 算法
 * @return 返回的消息认证码
 * @throws Exception
 */
 public static String generateHmac(String input,String keyString,String algorithm) throws Exception {
 Mac mac = Mac.getInstance(algorithm);
 Key key = new SecretKeySpec(keyString.getBytes(), "");
 mac.init(key);
 byte[] result = mac.doFinal(input.getBytes());
 String hmac = toHex(result);
 return hmac;
 }
 /**
 * 消息认证
 * @param input 原文
 * @param keyString 秘钥序列
 * @param algorithm 算法
 * @param hmac 传入的消息认证码
 * @return
 * @throws Exception
 */
 public static boolean verifyHamc(String input,String keyString,String algorithm,String hmac) throws Exception {
 String newHmac = generateHmac(input, keyString, algorithm);
 if (newHmac != null && newHmac.equals(hmac)) {
 return true;
 }
 return false;
 }
 // 将字节数组转为16进制字符串
 public static String toHex(byte[] digest) {
 StringBuilder sb = new StringBuilder();
 for (byte b : digest) {
 int i = b & 0xff;
 String s = Integer.toHexString(i);
 if (s.length() == 1) {
 s = "0" + s;
 }
 sb.append(s);
 }
 return sb.toString();
 }
}

数字签名

签名的生成和验证

  1. 签名
    • 有原始数据对其进行哈希运算 -> 散列值
    • 使用非对称加密的私钥对散列值加密 -> 签名
    • 将原始数据和签名一并发送给对方
  2. 验证
    • 接收数据
      • 原始数据
      • 数字签名
    • 数字签名, 需要使用公钥解密, 得到散列值
    • 对原始数据进行哈希运算得到新的散列值

非对称加密和数字签名

总结:

  1. 数据通信
  • 公钥加密, 私钥解密
  1. 数字签名:
  • 私钥加密, 公钥解密

数字签名的方法

Logo

  • 数字签名示例代码
public class SignatureDemo {
 public static void main(String[] args) throws Exception {
 String algorithm = "RSA";
 String priPath = "test.pri";
 String pubPath = "test.pub";
 String input = "frank";
// RSAUtil.generateKeys(algorithm,priPath,pubPath);
 PrivateKey privateKey = RSAUtil.getPrivateKey(priPath, algorithm);
 PublicKey publicKey = RSAUtil.getPublicKey(pubPath, algorithm);
 String signatureAlgorithm = "SHA256withRSA";
 String signatured = getSignature(input, privateKey, signatureAlgorithm);
 boolean verify = verifySignature(input, publicKey, signatureAlgorithm, signatured);
 System.out.println(verify);
 }
 /**
 * 生成签名字符串
 * @param input 原文
 * @param privateKey 私钥
 * @param signatureAlgorithm 签名算法
 * @return
 * @throws Exception
 */
 public static String getSignature(String input, PrivateKey privateKey, String signatureAlgorithm) throws Exception {
 Signature signature = Signature.getInstance(signatureAlgorithm);
 signature.initSign(privateKey);
 signature.update(input.getBytes());
 byte[] sign = signature.sign();
 return Base64.encode(sign);
 }
 /**
 * 校验签名
 * @param input 原文
 * @param publicKey 公钥
 * @param signatureAlgorithm 签名算法
 * @param signatured 发送过来的签名
 * @return
 * @throws Exception
 */
 public static boolean verifySignature(String input, PublicKey publicKey, String signatureAlgorithm, String signatured) throws Exception {
 Signature signature = Signature.getInstance(signatureAlgorithm);
 signature.initVerify(publicKey);
 signature.update(input.getBytes());
 return signature.verify(Base64.decode(signatured));
 }
}

About

java hash signature md5 sha1 sha256 rsa

Resources

Stars

Watchers

Forks

Packages

No packages published

AltStyle によって変換されたページ (->オリジナル) /