Java实现各种加密算法签名算法(AES、DES、ECC、RSA、ECIES、ECDSA等)

文中基于对称加密AES和非对称加密ECC为例,其他对称加密(DES等)和非对称加密(RSA等)同理。

1. 获取密钥

首先我们要学会获得算法密钥,这是最基础的,有了密钥才能去加密解密签名验签。

首先以AES为例:

1.1 获取AES密钥

  • 系统生成

    public static SecretKey generateKey(int keySize) throws NoSuchAlgorithmException {
        // 指定所用算法为AES,同理可以将"AES"换成"DES"
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        // jdk中AES密钥长度只能是三种:128、192、256 bits。加密速度依次递减,安全性依次递增
        keyGen.init(keySize);
        return keyGen.generateKey();
    }
    
  • 自定义

    private static SecretKeySpec String2Key(String password, int keySize) throws NoSuchAlgorithmException {
        // 先对password取哈希值,因为后面我们要截取
        MessageDigest digester = MessageDigest.getInstance("SHA-256");
        digester.update(password.getBytes(StandardCharsets.UTF_8));
        byte[] passwordHash = digester.digest();
        // 密钥长度依然受限,因此需要截取。keySize可以是16、24、32,分别对应128、192、256 bits的长度
        byte[] pwd = Arrays.copyOfRange(passwordHash, 0, keySize);
        return new SecretKeySpec(pwd, "AES");
    }
    

1.2 获取EC密钥

public static KeyPair initKey(int keySize) throws Exception {
    // 指定所用算法为EC,同理可以将"EC"换成"RSA"
    KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC");
    // 设置密钥长度, 常见ECC密钥长度:256、384、521
    keyPairGen.initialize(256);
    // 生成密钥对
    return keyPairGen.generateKeyPair();
}
// 从密钥对中获得公私钥
PublicKey publicKey = keypair.getPublic();
PrivateKey privateKey = keypair.getPrivate();

2. 加解密

javax.crypto.Cipher类是java自带的用来加解密的类,详情见官方文档:https://docs.oracle.com/en/java/javase/17/docs/api/java.base/javax/crypto/Cipher.html

使用主要分为三步:

  1. 获取算法实例(getInstance方法)
  2. 初始化(init方法)
  3. 加密或解密(doFinal方法)

2.1 AES加解密

获取算法实例用于加解密:

private static Cipher cipher; // 单例设计模式

static {
    try {
        cipher = Cipher.getInstance("AES");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

加密:

public static byte[] encrypt(String plainText, Key secretKey) throws Exception {
    // 因为明文和密码都是中文,所以这里用了UTF_8字符集
    byte[] data = plainText.getBytes(StandardCharsets.UTF_8);
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    return cipher.doFinal(data);
}

解密:

public static byte[] decrypt(byte[] ciphertext, Key secretKey) throws Exception {
    cipher.init(Cipher.DECRYPT_MODE, secretKey);
    return cipher.doFinal(ciphertext);
}

2.2 ECIES加解密

因为Java本地库不支持ECIES,所以我们需要引入第三方库,这里以BC库为例:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15to18</artifactId>
    <version>1.76</version>
</dependency>

然后我们在使用BC库前,需要将BC注册为提供者,我这里通过静态代码块进行注册:

// 这段代码块一定要放在最前面,因为注册是最基础的必须操作
static {
    Security.addProvider(new BouncyCastleProvider());
}

获取算法实例用于加解密:

private static Cipher cipher; // 单例设计模式

static {
    try {
        // 指定用BC库来支持ECIES,因此在这之前确保BC已经注册
        cipher = Cipher.getInstance("ECIES", "BC");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

加密:

public static byte[] encryptByPublicKey(String data, PublicKey publicKey) throws Exception {
    cipher.init(Cipher.ENCRYPT_MODE, publicKey, iesParameterSpec);
    return cipher.doFinal(data.getBytes());
}

解密:

public static byte[] decryptByPrivateKey(byte[] ciphertext, PrivateKey privateKey) throws Exception {
    cipher.init(Cipher.DECRYPT_MODE, privateKey, iesParameterSpec);
    return cipher.doFinal(ciphertext);
}

其中iesParameterSpec参数是IES参数,加解密的IES参数必须相同。

我因为是做实验,便将它设置为全局常量:

public static IESParameterSpec iesParameterSpec = new IESParameterSpec(
        null,
        null,
        256,
        256,
        null,
        false);

3. 签名和验签

java.security.Signature类是java自带的用来签名和验签的类,详情见官方文档:https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/security/Signature.html#sign()

使用主要分为四步:

  1. 获得算法实例(getInstance方法)
  2. 初始化(init方法)
  3. 更新(update方法)
  4. 签名或验签(sign或verify方法)

3.1 ECDSA数字签名

首先获取算法实例:

private static Signature signer; // 单例设计模式

static {
    try {
        signer = Signature.getInstance("SHA256withECDSA");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

签名:

public static byte[] sign(String message, PrivateKey privateKey) throws Exception {
    signer.initSign(privateKey);
    signer.update(message.getBytes(StandardCharsets.UTF_8));
    return signer.sign();
}

验签:

public static boolean verifySignature(String message, byte[] signature, PublicKey publicKey) throws Exception {
    signer.initVerify(publicKey);
    signer.update(message.getBytes(StandardCharsets.UTF_8));
    return signer.verify(signature);
}

如果对你有用请一件三连😊

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值