Java实现7种常见密码算法

本文详细介绍了Java Cryptography Architecture(JCA)框架下的密码算法,包括对称加密(如AES)、非对称加密(如RSA)、密码学哈希、消息认证码、数字签名、密钥协商算法以及基于口令加密PBE。通过Cipher、MessageDigest、MAC、Signature等类展示了具体实现,并讲解了密钥生成、读取、证书生成与读取的相关知识,如SecureRandom、KeyGenerator、KeyPairGenerator、KeyFactory等。文章还涵盖了常见的问题,如密文解密失败、签名验证失败和证书信任问题,提供了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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中的标准名称是什么,可以到 docs.oracle.com/en/java/jav… 中查询即可。

非对称加密

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

public byte[] encryptByPublicKey(byte[] data, PublicKey publicKey){
    try{
        Cipher cipher = Cipher.getInstance("RSA");
        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");
        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[] data, PublicKey publicKey, byte[] sign) {
    try {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(publicKey);
        signature.update(data);
        return signature.verify(sign);
    } catch (Exception e) {
        return ExceptionUtils.rethrow(e);
    }
}

密钥协商算法

在JCA中,使用KeyAgreement来调用密钥协商算法,以ECDH协商算法为例,如下:

public static void testEcdh() {
    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
    ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
    keyGen.initialize(ecSpec);
    // A生成自己的私密信息
    KeyPair keyPairA = keyGen.generateKeyPair();
    KeyAgreement kaA = KeyAgreement.getInstance("ECDH");
    kaA.init(keyPairA.getPrivate());
    // B生成自己的私密信息
    KeyPair keyPairB = keyGen.generateKeyPair();
    KeyAgreement kaB = KeyAgreement.getInstance("ECDH");
    kaB.init(keyPairB.getPrivate());

    // B收到A发送过来的公用信息,计算出对称密钥
    kaB.doPhase(keyPairA.getPublic(), true);
    byte[] kBA = kaB.generateSecret();

    // A收到B发送过来的公开信
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值