diff --git a/src/main/java/xyz/zhouxy/plusone/commons/security/RSA.java b/src/main/java/xyz/zhouxy/plusone/commons/security/RSA.java new file mode 100644 index 0000000..98944da --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/commons/security/RSA.java @@ -0,0 +1,104 @@ +package xyz.zhouxy.plusone.commons.security; + +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; + +import com.google.common.annotations.Beta; + +/** + * RSA 非对称加密。 + */ +@Beta +public class RSA { + private static final int DEFAULT_KEY_SIZE = 2048; + public static final String NAME = "RSA"; + private static final String TRANSFORMATION = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; + + private final PublicKey publicKey; + private final PrivateKey privateKey; + private final Cipher encryptModeCipher; + private final Cipher decryptModeCipher; + + private RSA(final PublicKey publicKey, final PrivateKey privateKey) + throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { + this.publicKey = publicKey; + this.privateKey = privateKey; + this.encryptModeCipher = Cipher.getInstance(TRANSFORMATION); + encryptModeCipher.init(Cipher.ENCRYPT_MODE, publicKey); + this.decryptModeCipher = Cipher.getInstance(TRANSFORMATION); + decryptModeCipher.init(Cipher.DECRYPT_MODE, privateKey); + } + + public static RSA of(final PublicKey publicKey, final PrivateKey privateKey) { + try { + return new RSA(publicKey, privateKey); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) { + throw new SecurityException(e); + } + } + + public static RSA of(final KeyPair keyPair) { + try { + return new RSA(keyPair.getPublic(), keyPair.getPrivate()); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) { + throw new SecurityException(e); + } + } + + public static RSA withKeySize(int keySize) { + try { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(NAME); + keyPairGenerator.initialize(keySize); + final KeyPair keyPair = keyPairGenerator.generateKeyPair(); + return new RSA(keyPair.getPublic(), keyPair.getPrivate()); + } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) { + throw new SecurityException(e); + } + } + + public static RSA withDefaultKeySize() { + return withKeySize(DEFAULT_KEY_SIZE); + } + + public PrivateKey getPrivateKey() { + return privateKey; + } + + public PublicKey getPublicKey() { + return publicKey; + } + + public byte[] encrypt(byte[] input) throws IllegalBlockSizeException, BadPaddingException { + return encryptModeCipher.doFinal(input); + } + + public byte[] encrypt(String input) throws IllegalBlockSizeException, BadPaddingException { + return encrypt(input.getBytes(StandardCharsets.UTF_8)); + } + + public String encryptToString(String input) throws IllegalBlockSizeException, BadPaddingException { + return new String(encrypt(input)); + } + + public byte[] decrypt(byte[] input) throws IllegalBlockSizeException, BadPaddingException { + return decryptModeCipher.doFinal(input); + } + + public byte[] decrypt(String input) throws IllegalBlockSizeException, BadPaddingException { + return decryptModeCipher.doFinal(input.getBytes(StandardCharsets.UTF_8)); + } + + public String decryptToString(String input) throws IllegalBlockSizeException, BadPaddingException { + return new String(decrypt(input)); + } +}