选择Java密码算法第1部分-散列

抽象

这是涵盖Java加密算法的三部分博客系列的第1部分。 本系列介绍如何实现以下目标:

  1. 使用SHA–512散列
  2. 使用AES–256的单密钥对称加密
  3. 使用RSA–4096的公钥/私钥非对称加密

这第一篇文章详细介绍了如何实现SHA–512哈希。 让我们开始吧。

免责声明

这篇文章仅供参考。 在使用所提供的任何信息之前,请认真思考。 从中学到东西,但最终自己做出决定,风险自负。

要求

我使用以下主要技术完成了本文的所有工作。 您可能可以使用不同的技术或版本来做相同的事情,但不能保证。

  • Java 1.8.0_152_x64
  • NetBeans 8.2(内部版本201609300101)
  • Maven 3.0.5(与NetBeans捆绑在一起)

下载

访问我的GitHub页面以查看我所有的开源项目。 这篇文章的代码位于项目中: thoth-cryptography

散列

关于

散列是一种单向密码算法,它接收任意长度的消息,并输出该消息的可重复,固定长度和单向摘要(哈希)。 作为单向方式,应该无法从哈希值中重新生成原始消息。 相同的消息将始终生成相同的哈希。

哈希可以用于验证原始消息。 哈希的一种常见用法是验证密码。 而不是存储密码本身,而是存储密码的哈希。 为了验证密码,在登录过程中将存储的哈希与输入密码的新哈希进行比较。

由于相同的消息会生成相同的哈希,因此将使用salt值使哈希更安全(Salt,2017,第1段)。 考虑多个用户使用相同密码的情况。 盐值与原始密码结合使用可实现唯一的哈希值。 这很重要,因为如果散列值曾经遭到破坏,则相同的哈希值会让黑客知道那些密码是相同的。

SHA–512

截至今天进行的研究似乎表明,哈希算法的最佳和最安全算法是SHA–512,它使用64位字(Secure Hash Algorithms,2017,第2段)。 让我们看一个例子。

注意请勿将MD5用作安全哈希。 它具有许多漏洞(MD5,2017年,第1段)。 将MD5的使用限制为校验和和数据验证。

清单1是ShaTest.java单元测试,演示了如何哈希。 清单2是执行哈希的Sha.java类。

清单1 – ShaTest.java类

package org.thoth.security.hash;

import java.util.Optional;
import org.junit.Assert;
import org.junit.Test;

/**
 * @author Michael Remijan mjremijan@yahoo.com @mjremijan
 */
public class ShaTest {

    @Test
    public void test_hash_with_optional_to_hex() throws Exception {
        // setup
        String username = "mjremijan";
        String password = "super!secret";
        Sha sha = new Sha();

        // test
        String asHex
            = sha.hashToHex(password, Optional.of(username));

        // assert
        Assert.assertEquals(
              "F38CD5290D11B20159E36740843A8D93CFDFA395CF594F328613EF5C7BA42D9EAC00BF3EE47B7E8CE1587040B36365F05C8E15E9392C288A1D7C4CFB66097848"
            , asHex);
    }

    @Test
    public void test_hash_without_optional_to_hex() throws Exception {
        // setup
        String password = "super!secret";
        Sha sha = new Sha();

        // test
        String asHex
            = sha.hashToHex(password, Optional.empty());

        // assert
        Assert.assertEquals(
              "516A1FE9D87FE5B953D91B48B1A2FFA5AE5F670914C1B6FE0835D8877918DC4E8BC8FB8CCD520DBA940C21B4F294DFD1B4EFF2E06AB110C6A06E35068251C1DD"
            , asHex);
    }


    @Test
    public void test_hash_with_optional_to_base64() throws Exception {
        // setup
        String username = "mjremijan";
        String password = "super!secret";
        Sha sha = new Sha();

        // test
        String asBase64
            = sha.hashToBase64(password, Optional.of(username));

        // assert
        Assert.assertEquals(
              "84ZVKQ0RSGFZ42DAHDQNK8/FO5XPWU8YHHPVXHUKLZ6SAL8+5HT+JOFYCECZY2XWXI4V6TKSKIODFEZ7ZGL4SA=="
            , asBase64);
    }


    @Test
    public void test_hash_without_optional_to_base64() throws Exception {
        // setup
        String password = "super!secret";
        Sha sha = new Sha();

        // test
        String asBase64
            = sha.hashToBase64(password, Optional.empty());

        // assert
        Assert.assertEquals(
              "UWOF6DH/5BLT2RTISAL/PA5FZWKUWBB+CDXYH3KY3E6LYPUMZVINUPQMIBTYLN/RTO/Y4GQXEMAGBJUGGLHB3Q=="
            , asBase64);
    }
}

清单2 – Sha.java类

package org.thoth.security.hash;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Optional;

/**
 * @author Michael Remijan mjremijan@yahoo.com @mjremijan
 */
public class Sha {

    public String hashToHex(String hashMe, Optional<String> salt)
    throws NoSuchAlgorithmException, UnsupportedEncodingException {
        byte[] bytes
            = hash(hashMe, salt);

        StringBuilder sp
            = new StringBuilder();

        for (int i = 0; i < bytes.length; i++) {
            sp.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
        }

        return sp.toString().toUpperCase();
    }

    public String hashToBase64(String hashMe, Optional<String> salt)
    throws NoSuchAlgorithmException, UnsupportedEncodingException {
        return Base64.getEncoder().encodeToString(
            hash(hashMe, salt)
        ).toUpperCase();
    }

    public byte[] hash(String hashMe, Optional<String> salt)
    throws NoSuchAlgorithmException, UnsupportedEncodingException {
        MessageDigest md
            = MessageDigest.getInstance("SHA-512");

        md.update(hashMe.getBytes("UTF-8"));
        salt.ifPresent(s -> {
            try { md.update(s.getBytes("UTF-8")); } catch (Exception e) {throw new RuntimeException(e);}
        });

        return md.digest();
    }
}

摘要

哈希很容易。 选择一种强大的哈希算法(例如SHA–512)来保护您的应用程序数据。 避免使用MD5来保护数据。 及时了解哪些算法强大且安全。 如果您使用的是较旧的算法存在漏洞或受到威胁,请更新您的应用程序。

参考文献

盐(加密)。 (2017年11月3日)。 维基百科。 取自https://en.wikipedia.org/wiki/Salt_(cryptography)

安全哈希算法。 (2017年11月25日)。 维基百科。 取自https://en.wikipedia.org/wiki/Secure_Hash_Algorithms

MD5。 (2017年11月22日)。 维基百科。 取自https://en.wikipedia.org/wiki/MD5

翻译自: https://www.javacodegeeks.com/2017/12/choosing-java-cryptographic-algorithms-part-1-hashing.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值