Java实现7种常见密码算法

原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。

简介

前面在密码学入门一文中讲解了各种常见的密码学概念、算法与运用场景,但没有介绍过代码,因此,为作补充,这一篇将会介绍使用Java语言如何实现使用这些算法,并介绍一下使用过程中可能遇到的坑。

Java加密体系JCA

Java抽象了一套密码算法框架JCA(Java Cryptography Architecture),在此框架中定义了一套接口与类,以规范Java平台密码算法的实现,而Sun,SunRsaSign,SunJCE这些则是一个个JCA的实现Provider,以实现具体的密码算法,这有点像List与ArrayList、LinkedList的关系一样,Java开发者只需要使用JCA即可,而不用管具体是怎么实现的。

JCA里定义了一系列类,如Cipher、MessageDigest、MAC、Signature等,分别用于实现加密、密码学哈希、认证码、数字签名等算法,一起来看看吧!

对称加密

对称加密算法,使用Cipher类即可,以广泛使用的AES为例,如下:

public byte[] encrypt(byte[] data, Key key) {
   
    try {
   
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] iv = SecureRandoms.randBytes(cipher.getBlockSize());
        //初始化密钥与加密参数iv
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
        //加密
        byte[] encryptBytes = cipher.doFinal(data);
        //将iv与密文拼在一起
        ByteArrayOutputStream baos = new ByteArrayOutputStream(iv.length + encryptBytes.length);
        baos.write(iv);
        baos.write(encryptBytes);
        return baos.toByteArray();
    } catch (Exception e) {
   
        return ExceptionUtils.rethrow(e);
    }
}

public byte[] decrypt(byte[] data, Key key) {
   
    try {
   
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        //获取密文前面的iv
        IvParameterSpec ivSpec = new IvParameterSpec(data, 0, cipher.getBlockSize());
        cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
        //解密iv后面的密文
        return cipher.doFinal(data, cipher.getBlockSize(), data.length - cipher.getBlockSize());
    } catch (Exception e) {
   
                return ExceptionUtils.rethrow(e);
    }
}

如上,对称加密主要使用Cipher,不管是AES还是DES,Cipher.getInstance()传入不同的算法名称即可,这里的Key参数就是加密时使用的密钥,稍后会介绍它是怎么来的,暂时先忽略它。
另外,为了使得每次加密出来的密文不同,我使用了随机的iv向量,并将iv向量拼接在了密文前面。

注:如果某个算法名称,如上面的AES/CBC/PKCS5Padding,你不知道它在JCA中的标准名称是什么,可以到 https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html 中查询即可。

非对称加密

非对称加密同样是使用Cipher类,只是传入的密钥对象不同,以RSA算法为例,如下:

public byte[] encryptByPublicKey(byte[] data, PublicKey publicKey){
   
    try{
   
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }catch (Exception e) {
   
        throw Errors.toRuntimeException(e);
    }
}

public byte[] decryptByPrivateKey(byte[] data, PrivateKey privateKey){
   
    try{
   
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }catch (Exception e) {
   
        throw Errors.toRuntimeException(e);
    }
}

一般来说应使用公钥加密,私钥解密,但其实反过来也是可以的,这里的PublicKey与PrivateKey也先忽略,后面会介绍它怎么来的。

密码学哈希

密码学哈希算法包括MD5、SHA1、SHA256等,在JCA中都使用MessageDigest类即可,如下:

public static String sha256(byte[] bytes) throws NoSuchAlgorithmException {
   
    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    digest.update(bytes);
    return Hex.encodeHexString(digest.digest());
}

消息认证码

消息认证码使用Mac类实现,以常见的HMAC搭配SHA256为例,如下:

public byte[] digest(byte[] data, Key key) throws InvalidKeyException, NoSuchAlgorithmException{
   
    Mac mac = Mac.getInstance("HmacSHA256");
    mac.init(key);
    return mac.doFinal(data);
}

数字签名

数字签名使用Signature类实现,以RSA搭配SHA256为例,如下:

public byte[] sign(byte[] data, PrivateKey privateKey) {
   
    try {
   
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(data);
        return signature.sign();
    } catch (Exception e) {
   
        return ExceptionUtils.rethrow(e);
    }
}

public boolean verify(byte
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值