如何从 .key 文件加载私钥

Posted

技术标签:

【中文标题】如何从 .key 文件加载私钥【英文标题】:how to load Private Key from .key file 【发布时间】:2020-08-28 21:19:48 【问题描述】:

我想从 .key 文件加载 PrivateKey 并使用它来生成 jwt 令牌。 我有以下方法来生成令牌

    public String gen(String privateFile, String crtFile) 

        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        long expMillis = nowMillis + 50000;
        Date exp = new Date(expMillis);

        // load private key
        PrivateKey privKey= loadPrivateKey(privateFile);
        // load public key
        PublicKey pubKey= loadPublicKey(crtFile);

        String jws = Jwts.builder()
                .setSubject(jwtSubject)
                .setAudience(jwtAudience)
                .setExpiration(exp)
                .setIssuedAt(now)
                .setIssuer(jwtIssuer)
                .setNotBefore(now)
                .signWith(privKey, SignatureAlgorithm.RS512)
                .compact();

        return jws;


loadPrivateKey 方法如下:

    public static PrivateKey loadPrivateKey(String filename)
        throws Exception 

    String privateKeyContent = new String(Files.readAllBytes(Paths.get(ClassLoader.getSystemResource(filename).toURI())));
    privateKeyContent = privateKeyContent.replaceAll("\\n", "").replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "");

    KeyFactory kf = KeyFactory.getInstance("RSA");
    PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyContent));

    PrivateKey privKey = kf.generatePrivate(keySpecPKCS8);
    return privKey;


在编译时我得到java.io.IOException: Invalid keystore format at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:663) at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:56) at sun.security.provider.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:224) at sun.security.provider.JavaKeyStore$DualFormatJKS.engineLoad(JavaKeyStore.java:70)

我不明白,因为我正在打开 PKCS8 私钥。有人知道如何解决这个问题吗?

【问题讨论】:

【参考方案1】:

我希望这将帮助您生成令牌。 将.key.der 文件保存到类路径src/main/resources 中。

public class JWTClientService 

    public String generateJWTToken(ProjectConfig jwtConfig) 
        return Jwts.builder()
                .setSubject(jwtConfig.getSubject())
                .setIssuer(jwtConfig.getIssuer())
                .setExpiration(getExpiryDate(jwtConfig.getTokenExpiryUnit(), jwtConfig.getTokenExpiryFrequency()))
                .setAudience(jwtConfig.getAudience())
                .claim(jwtConfig.getClaimKey(), Boolean.valueOf(jwtConfig.getClaimValue()))
                .signWith(SignatureAlgorithm.RS512, privateKey(jwtConfig))
                .compact();
    

    private Date getExpiryDate(String tokenExp, String tokenExpFreq) 
        Calendar calendar = Calendar.getInstance();
        int expiry = Integer.parseInt(tokenExp);
        switch (tokenExpFreq.toLowerCase()) 

            case "second": 
                calendar.add(Calendar.SECOND, expiry);
                break;
            
            case "minute": 
                calendar.add(Calendar.MINUTE, expiry);
                break;
            
            case "hour": 
                calendar.add(Calendar.HOUR, expiry);
                break;
            
            case "day": 
                calendar.add(Calendar.DATE, expiry);
                break;
            
            case "month": 
                calendar.add(Calendar.MONTH, expiry);
                break;
            
            default: 
                calendar.add(Calendar.HOUR, expiry);
                break;
            
        
        return calendar.getTime();
    

    private PrivateKey privateKey(ProjectConfig jwtConfig) 
        PrivateKey privateKey = null;
        try 
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(jwtConfig.getKeyPath());
            ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
            assert inputStream != null;
            IOUtils.copy(inputStream, byteOutputStream);
            byte[] privKeyByteArray = byteOutputStream.toByteArray();
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyByteArray);

            KeyFactory keyFactory = KeyFactory.getInstance(jwtConfig.getKeyAlgorithm());

            privateKey = keyFactory.generatePrivate(keySpec);
         catch (Exception ex) 
            throw new RuntimeException("Unable to generate private key..." + ex.getMessage());
        
        return privateKey;
    


找到项目配置类:

 @JsonInclude(JsonInclude.Include.NON_NULL)
    public class ProjectConfig 
        private String clientId;
        private String clientSecret;
        private String jwtTokenUrl;
        private String keyAlgorithm;
        private String keyPath;
        private String subject;
        private String issuer;
        private String audience;
        private String claimKey;
        private String claimValue;
        private String tokenExpiryFrequency;
        private String tokenExpiryUnit;

        public String getClientId() 
            return clientId;
        

        public void setClientId(String clientId) 
            this.clientId = clientId;
        

        public String getClientSecret() 
            return clientSecret;
        

        public void setClientSecret(String clientSecret) 
            this.clientSecret = clientSecret;
        

        public String getJwtTokenUrl() 
            return jwtTokenUrl;
        

        public void setJwtTokenUrl(String jwtTokenUrl) 
            this.jwtTokenUrl = jwtTokenUrl;
        

        public String getKeyAlgorithm() 
            return keyAlgorithm;
        

        public void setKeyAlgorithm(String keyAlgorithm) 
            this.keyAlgorithm = keyAlgorithm;
        

        public String getKeyPath() 
            return keyPath;
        

        public void setKeyPath(String keyPath) 
            this.keyPath = keyPath;
        

        public String getSubject() 
            return subject;
        

        public void setSubject(String subject) 
            this.subject = subject;
        

        public String getIssuer() 
            return issuer;
        

        public void setIssuer(String issuer) 
            this.issuer = issuer;
        

        public String getAudience() 
            return audience;
        

        public void setAudience(String audience) 
            this.audience = audience;
        

        public String getClaimKey() 
            return claimKey;
        

        public void setClaimKey(String claimKey) 
            this.claimKey = claimKey;
        

        public String getClaimValue() 
            return claimValue;
        

        public void setClaimValue(String claimValue) 
            this.claimValue = claimValue;
        

        public String getTokenExpiryFrequency() 
            return tokenExpiryFrequency;
        

        public void setTokenExpiryFrequency(String tokenExpiryFrequency) 
            this.tokenExpiryFrequency = tokenExpiryFrequency;
        

        public String getTokenExpiryUnit() 
            return tokenExpiryUnit;
        

        public void setTokenExpiryUnit(String tokenExpiryUnit) 
            this.tokenExpiryUnit = tokenExpiryUnit;
        
    

主类:

public class TokenApplication 
    static ObjectMapper objectMapper = new ObjectMapper()
            .configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);

    public static void main(String[] args) 
        ProjectConfig projectConfig = loadConfiguration("application-stg.properties");

        if (args.length > 0 && args[0].equals("PROD")) 
            projectConfig = loadConfiguration("application-prod.properties");
        
        try 
            JWTTokenService jwtTokenService = new JWTTokenService();
            System.out.println(jwtTokenService.getJwtToken(projectConfig).getAccessToken());
            System.exit(JobStatus.SUCCESS.getCode());
         catch (Exception ex) 
            System.exit(JobStatus.PROCESS_FAILED.getCode());
        

    


    private static ProjectConfig loadConfiguration(String filePath) 
        try (InputStream input = TokenApplication.class.getClassLoader().getResourceAsStream(filePath)) 
            Properties props = new Properties();
            props.load(input);
            return objectMapper.convertValue(new HashMap(props), ProjectConfig.class);
         catch (Exception ex) 
            throw new RuntimeException("Not able to load configuration" + ex.getMessage());
        
    


应用程序-stg.properties

keyAlgorithm=RSA
keyPath=private-stage.der
subject=
issuer=
audience=
claimKey=
claimValue=true
tokenExpiryFrequency=DAY
tokenExpiryUnit=1
clientId=
clientSecret=
jwtTokenUrl=

【讨论】:

以上是关于如何从 .key 文件加载私钥的主要内容,如果未能解决你的问题,请参考以下文章

Perl 和 .NET RSA 一起工作?从 Perl 公钥在 .NET 中加密?从 Perl 加载私钥?

如何使用我的私钥文件加载我的 Solana 钱包?

如何从 PHP 文件加载返回数组?

如何编写将返回包含从文本文件加载的数据的字典的函数

从私钥生成CSR的OpenSSL错误

在文件中保存/加载私钥和公钥