使用RSA生成公钥和私钥

1.jdk keytool

可以用keytool工具直接生成,需要openssl工具Binaries – OpenSSLWiki设置到环境变量里

@echo off
cd ../output
IF exist auth.jks del auth.jks
IF exist auth.key del auth.key
keytool -genkeypair -alias xxxx_key -keyalg RSA -keypass xxxxxx -keystore auth.jks -storepass xxxxxx -dname CN=xxx
keytool -list -rfc --keystore auth.jks -storepass xxxxxx | openssl x509 -inform pem -pubkey > temp.key
(@FOR /f "tokens=1* delims=:" %%a IN ('findstr /n "^" "temp.key"') DO @IF %%a leq 9 ECHO(%%b) > auth.key
del temp.key
echo Build OK!
pause

 2.认证与鉴权使用

生成的authkey放到gateway下,生成的auth.jks放到auth认证服务下

网关结合鉴权,需要配置如下配置文件                

spring:
    security:
        oauth2:
            resourceserver:
                jwt:
                    public-key-location: classpath:auth.key

认证服务配置Bean

    @Bean
    public JWKSource<SecurityContext> jwkSource() throws Exception {

        KeyStore keyStore = KeyStore.getInstance("JKS");
        // 取得JKS文件
        Resource resource = new ClassPathResource(DEFAULT_KEY_STORE_FILE);
        if (!resource.exists()) {
            resource = new FileSystemResource(DEFAULT_KEY_STORE_FILE);
        }
        try (InputStream inputStream = resource.getInputStream()) {
            keyStore.load(inputStream, DEFAULT_KEY_STORE_PASSWORD.toCharArray());
            RSAPublicKey publicKey = (RSAPublicKey) keyStore.getCertificate(DEFAULT_KEY_ALIAS).getPublicKey();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyStore.getKey(DEFAULT_KEY_ALIAS, DEFAULT_KEY_PASSWORD.toCharArray());
            RSAKey rsaKey = new RSAKey.Builder(publicKey)
                    .privateKey(privateKey)
                    .keyStore(keyStore)
                    .build();
            JWKSet jwkSet = new JWKSet(rsaKey);
            return new ImmutableJWKSet<>(jwkSet);
        }
    }

3.工程项目直接生成

接口AuthToolController

package xxx.authtool.controller;

import xxx.authtool.util.RsaUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.security.KeyPair;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@RestController
@RequestMapping("/generate")
public class AuthToolController {

    @Value("${file-path:}")
    private String filePath;

    /**
     * 创建并下载auth.key和auth.jks
     * @param days 创建证书的有效期 单位:天 不传默认90天
     * @param response http返回值
     * @throws IOException 异常
     */
    @GetMapping("/downloadAuthKeyZip")
    public void downloadAuthKeyZip(@RequestParam(required = false) Integer days, HttpServletResponse response) throws IOException {

        String dirPath = mkdir();
        // 创建一个临时zip文件,用于存放要下载的多个文件
        File zipFile = new File(dirPath + "/" + "authKeys.zip");

        // 获取需要下载的多个文件,并将它们添加到zip文件中
        List<File> filesToDownload = getFilesToDownload(dirPath, days);
        addFilesToZip(filesToDownload, zipFile);
        deleteFiles(filesToDownload);

        //设置响应头信息
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=authKeys.zip");

        // 将zip文件内容写入到HttpServletResponse输出流中,实现文件下载
        try (InputStream inputStream = Files.newInputStream(zipFile.toPath());
             OutputStream outputStream = response.getOutputStream()) {
            byte[] buffer = new byte[4096];
            int length;
            while ((length = inputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, length);
                outputStream.flush();
            }
        }
    }

    /**
     * 删除文件
     * @param filesToDownload 文件列表
     */
    private void deleteFiles(List<File> filesToDownload) {
        for (File file : filesToDownload) {
            file.delete();
        }
    }

    /**
     * 获取文件列表
     * @param dirPath 文件路径
     * @param days 时间
     * @return 文件列表
     */
    private List<File> getFilesToDownload(String dirPath, Integer days) {
        // 获取需要下载的多个文件
        List<File> files = new ArrayList<>();
        KeyPair keyPair = RsaUtil.genKeyPair();

        File publicFile = RsaUtil.genPublicFile(keyPair, dirPath);
        File privateFile = RsaUtil.genPrivateFile(keyPair, dirPath, days);

        files.add(publicFile);
        files.add(privateFile);
        return files;
    }


    /**
     * 压缩文件
     * @param filesToDownload 文件列表
     * @param zipFile 压缩文件
     * @throws IOException 异常
     */
    private void addFilesToZip(List<File> filesToDownload, File zipFile) throws IOException {
        // 将多个文件压缩到zip文件中
        try (ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(zipFile.toPath()))) {
            for (File file : filesToDownload) {
                zipOutputStream.putNextEntry(new ZipEntry(file.getName()));
                try (FileInputStream inputStream = new FileInputStream(file)) {
                    byte[] buf = new byte[1024];
                    int len;
                    while ((len = inputStream.read(buf)) > 0) {
                        zipOutputStream.write(buf, 0, len);
                    }
                }
                zipOutputStream.closeEntry();
            }
        }
    }

    /**
     * 创建文件夹
     * @return 文件路径
     */
    private String mkdir() {
        String dateString = getDateString();
        // 文件夹路径
        String dirPath = filePath + "/" + dateString;

        File directory = new File(dirPath);
        // 判断文件夹是否存在
        if (!directory.exists()) {
            // 创建文件夹及其父目录
            directory.mkdirs();
        }
        return dirPath;
    }


    /**
     * 获取日期字符串
     * @return 日期字符串
     */
    private String getDateString() {
        Date currentDate = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
        return dateFormat.format(currentDate);
    }
}

RSAUtil

package xxx.authtool.util;

import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import sun.security.x509.X500Name;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Date;

/**
 * RSA工具类
 *
 * @author xxx
 */
public final class RsaUtil {

    public static final String DEFAULT_KEY_STORE_FILE = "auth.jks";
    public static final String DEFAULT_KEY_FILE = "auth.key";

    public static final String DEFAULT_KEY_STORE_PASSWORD = "xxxxxx";

    public static final String DEFAULT_KEY_ALIAS = "xxxx";

    public static final String DEFAULT_KEY_PASSWORD = "xxxxxx";


    /**
     * 随机生成密钥对
     */
    public static KeyPair genKeyPair() {
        try {
            // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
            // 初始化密钥对生成器,密钥大小为96-1024位
            keyPairGen.initialize(2048, new SecureRandom());
            // 生成一个密钥对,保存在keyPair中
            return keyPairGen.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 生成私钥
     * @param keyPair 密钥对
     * @param dirPath 文件列表
     * @param days 时间
     * @return 秘钥文件
     */
    public static File genPrivateFile(KeyPair keyPair, String dirPath, Integer days) {
        File file = new File(dirPath + "/" + DEFAULT_KEY_STORE_FILE);
        try (FileOutputStream fos = new FileOutputStream(file)) {
            KeyStore keyStore = KeyStore.getInstance("JKS");

            keyStore.load(null, DEFAULT_KEY_PASSWORD.toCharArray());
            // 得到私钥
            PrivateKey privateKey = keyPair.getPrivate();
            // 为以下对象生成 2048 位RSA密钥对和自签名证书 (SHA256withRSA) (有效期为 90 天):
            String dn = "CN=xxxx";
            // 有效期默认为 90 天
            int day = 90;
            if (days != null) {
                day = days;
            }
            X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
                    new X500Name(dn).asX500Principal(),
                    BigInteger.valueOf(System.currentTimeMillis()),
                    new Date(System.currentTimeMillis()),
                    new Date(System.currentTimeMillis() + day * 24 * 60 * 60 * 1000L),
                    new X500Name(dn).asX500Principal(),
                    keyPair.getPublic());

            ContentSigner signer =
                    new JcaContentSignerBuilder("SHA256withRSA").setProvider(new BouncyCastleProvider()).build(keyPair.getPrivate());

            Certificate cert = new JcaX509CertificateConverter().setProvider(new BouncyCastleProvider()).getCertificate(builder.build(signer));

            keyStore.setKeyEntry(DEFAULT_KEY_ALIAS, privateKey, DEFAULT_KEY_PASSWORD.toCharArray(), new Certificate[]{cert});

            keyStore.store(fos, DEFAULT_KEY_STORE_PASSWORD.toCharArray());
            return file;
        } catch (KeyStoreException | IOException | CertificateException | NoSuchAlgorithmException |
                 OperatorCreationException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 生成公钥文件
     * @param keyPair 密钥对
     * @param dirPath 文件列表
     * @return 公钥文件
     */
    public static File genPublicFile(KeyPair keyPair, String dirPath) {
        try (StringWriter sw = new StringWriter()) {
            // 得到公钥
            PublicKey publicKey = keyPair.getPublic();
            // 获取PublicKey并将其转换为PEM格式的字符串
            try (JcaPEMWriter pemWriter = new JcaPEMWriter(sw)) {
                pemWriter.writeObject(publicKey);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            File file = new File(dirPath + "/" + DEFAULT_KEY_FILE);

            try (FileWriter fw = new FileWriter(file.getAbsoluteFile(), true);
                 BufferedWriter bw = new BufferedWriter(fw)
            ) {
                bw.write(sw.toString());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return file;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

依赖

	implementation 'org.bouncycastle:bcprov-jdk15on:1.69'
	implementation 'org.bouncycastle:bcpkix-jdk15on:1.69'

访问localhost:6080/generate/downloadAuthKeyZip可获取90天许可的证书

4.RSA工具类

package xxx.socket.stomp.config;

import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.springframework.util.Assert;

/**
 * RSA工具类
 *
 */
public class RsaUtils {

    private static String publicKeyStr = "";
    private static String privateKeyStr = "";

    public static void main(String[] args) {

        genKeyPair();

        String password = "xxxx";
        String rawPassword = encrypt(password);
        String password2 = decrypt(rawPassword);
        Assert.isTrue(password.equals(password2), "Error");
    }

    public static String encrypt(String password) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyStr));
            PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] passwordBytes = cipher.doFinal(password.getBytes(StandardCharsets.UTF_8));
            String result = new String(Base64.getEncoder().encode(passwordBytes), StandardCharsets.UTF_8);
            System.out.println("Encrypt Password: " + result);
            return result;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            System.out.println("Algorithm Error\n" + e);
        } catch (NoSuchPaddingException | InvalidKeyException e) {
            System.out.println("Cipher Error\n" + e);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            System.out.println("Password Error\n" + e);
        }
        return null;
    }

    public static String decrypt(String password) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyStr));
            PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] passwordBytes = cipher.doFinal(Base64.getDecoder().decode(password.getBytes(StandardCharsets.UTF_8)));
            String result = new String(passwordBytes, StandardCharsets.UTF_8);
            System.out.println("Decrypt Password: " + result);
            return result;
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            System.out.println("Algorithm Error\n" + e);
        } catch (NoSuchPaddingException | InvalidKeyException e) {
            System.out.println("Cipher Error\n" + e);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            System.out.println("Password Error\n" + e);
        }
        return null;
    }

    /**
     * 随机生成密钥对
     */
    public static void genKeyPair() {
        try {
            // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
            // 初始化密钥对生成器,密钥大小为96-1024位
            keyPairGen.initialize(2048, new SecureRandom());
            // 生成一个密钥对,保存在keyPair中
            KeyPair keyPair = keyPairGen.generateKeyPair();
            // 得到私钥
            PrivateKey privateKey = keyPair.getPrivate();
            // 得到公钥
            PublicKey publicKey = keyPair.getPublic();

            String publicKeyString = new String(Base64.getEncoder().encode(publicKey.getEncoded()));
            // 得到私钥字符串
            String privateKeyString = new String(Base64.getEncoder().encode((privateKey.getEncoded())));
            System.out.println("随机生成的公钥为:" + publicKeyString);
            System.out.println("随机生成的私钥为:" + privateKeyString);
            publicKeyStr = publicKeyString;
            privateKeyStr = privateKeyString;
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
}

5. 参考资料

www.php1.cn/detail/Java_ShiYong_key_81410199.html

版权声明:本文为博主作者:Domerobin原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/weixin_40240897/article/details/130241979

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2024年1月6日
下一篇 2024年1月6日

相关推荐