当前位置: 首页 > 知识库问答 >
问题:

使用模数和指数创建Google登录公钥的通用方法

詹联
2023-03-14

我想在这里从Google登录的JWK数据手动生成公钥;https://www.googleapis.com/oauth2/v3/certs

{
  "n": "3aOynmXd2aSH0ZOd0TIYd5RRaNXhLW306dlYw26nMp6QPGaJuOeMhTO3BO8Zt_ncRs4gdry4mEaUOetCKTUOyCCpIM2JAn0laN_iHfGKTYsNkjr16FiHWYJmvNJ1Q1-XXjWqNNKMFIKHKtMrsP2XPVD6ufp-lNQmt4Dl0g0qXJ4_Y_CKuP-uSlFWZuJ_0_2ukUgevvKtOZNcbth0iOiFalBRDr-2i1eNSJWOknEphy7GRs-JGPboTdHC7A3b-0dVFGMEMJFhxcEJHJgLCsQGdYdkphLJ5f21gCNdhp3g16H3Cqts2KTXgO4Rr8uhwZx5yiUjTuizD9wc7uDso4UJ7Q",
  "use": "sig",
  "kty": "RSA",
  "kid": "b6f8d55da534ea91cb2cb00e1af4e8e0cdeca93d",
  "alg": "RS256",
  "e": "AQAB"
},

我应该如何使用模数和指数来创建密钥?

在这个问题上,我尝试了以下步骤;从模和指数生成RSA公钥,但我的郎说给定的模不是十六进制字符串。还有一些信息缺失,比如berData函数是什么。

我在这里看到的类似问题的所有解决方案似乎都是特定于语言/框架的。我非常喜欢一些我可以遵循的伪代码。

共有2个答案

阎鸿煊
2023-03-14

在Crystal lang中有一个非常简化的实现

require "base64"
 
pp! jwk = {
  "n": "3aOynmXd2aSH0ZOd0TIYd5RRaNXhLW306dlYw26nMp6QPGaJuOeMhTO3BO8Zt_ncRs4gdry4mEaUOetCKTUOyCCpIM2JAn0laN_iHfGKTYsNkjr16FiHWYJmvNJ1Q1-XXjWqNNKMFIKHKtMrsP2XPVD6ufp-lNQmt4Dl0g0qXJ4_Y_CKuP-uSlFWZuJ_0_2ukUgevvKtOZNcbth0iOiFalBRDr-2i1eNSJWOknEphy7GRs-JGPboTdHC7A3b-0dVFGMEMJFhxcEJHJgLCsQGdYdkphLJ5f21gCNdhp3g16H3Cqts2KTXgO4Rr8uhwZx5yiUjTuizD9wc7uDso4UJ7Q",
  "use": "sig",
  "kty": "RSA",
  "kid": "b6f8d55da534ea91cb2cb00e1af4e8e0cdeca93d",
  "alg": "RS256",
  "e": "AQAB"
}
 
mod_hex = Base64.decode(jwk["n"]).hexstring
exp_hex = Base64.decode(jwk["e"]).hexstring
 
pub_key_hex = "30820122300D06092A864886F70D01010105000382010F003082010A0282010100" + mod_hex + "0203" + exp_hex
 
pp! pub_key = Base64.encode(String.new(pub_key_hex.hexbytes))
史承福
2023-03-14

原来这个问题已经有了答案,所以在很大程度上-https://stackoverflow.com/a/29707204/2862341.

在这一点上,它做得比我想象的要好得多。

为了向您提供完成任务所需的其他细节,我认为JWT编码是base64 url编码的(https://stackoverflow.com/a/55389212/2862341).

为了完整起见,这里还有一个示例java代码

package com.example.so.q68285091;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;


/*

------------------------------------------
https://www.googleapis.com/oauth2/v3/certs
------------------------------------------

{
  "keys": [
    {
      "kid": "1bf8a84d3ecd77e9f2ad5f06ffd260701dd06d90",
      "use": "sig",
      "n": "zw_voGnxIrSEnta0BxsS4Gmr0t106iCjmIK6nciUuppcUrDTKT3t3sZLsZ5Hl-WFzkGpo9u6jWj3ul64hcpgFTRJk5xIUnbKZ20za_IRfWDTZqhZ3LqeHqBQaw0BekUzICsw6Ip1-3kg3QoQyoU973Os6MAfpOP7SafcHp_tTRoMFAc7R3AWZdCmlMmw-xYLTT3UdI2hycXbTYOitFkCTYO4pL62IBt5inlOup4dk0HwazBp0zMYxyb49y1gqh_rfpswTSA7lVzySyU9SoXAWFHZW4rQrhiXwLOPz8cynr67lE5_D5t0XhLTfn5R2eV4k8bIpfoSDtMPHm-azuQnuQ",
      "e": "AQAB",
      "kty": "RSA",
      "alg": "RS256"
    },
    {
      "kty": "RSA",
      "n": "nQPB_WqGG18pjGSFGQwRLcZkcRojHHweN27mV1oTNeeH2quq5NvWibLEheiukVP60nXcGNpkP_PaycYahEfvAnJGLX_IscGAOJ67WWFs4M8wXHH6g2mTnalcAYgmpN1QDMVgz4NcWISXNTR-8FZfWgFN4LDZgK4f0wXOaJlh_Bzh-plPLJQUXyY7mZTEVsH8X3wg2fvV0Hxj_HudjgFlYPdDri1Oi4vI0wiKV4nJCRZ-INH3OIvPl-05WVjZ-XTSXdNjLNx35NM2Npcrr9VpZ8Xeg7pr0wjamqd_07xfEAdtFxsN6Ay6Ecz3k0onQP-6SLRCGLrMAxifziivmmafCQ",
      "e": "AQAB",
      "use": "sig",
      "kid": "7f548f6708690c21120b0ab668caa079acbc2b2f",
      "alg": "RS256"
    }
  ]
}

------------------------------------------

Output:
-------

X509 Public Key :
-----BEGIN PUBLIC KEY-----
MIIBejANBgkqhkiG9w0BAQEFAAOCAWcAMIIBYgKCAVh6dy92b0dueElyU0VudGEw
QnhzUzRHbXIwdDEwNmlDam1JSzZuY2lVdXBwY1VyRFRLVDN0M3NaTHNaNUhsK1dG
emtHcG85dTZqV2ozdWw2NGhjcGdGVFJKazV4SVVuYktaMjB6YS9JUmZXRFRacWha
M0xxZUhxQlFhdzBCZWtVeklDc3c2SXAxKzNrZzNRb1F5b1U5NzNPczZNQWZwT1A3
U2FmY0hwL3RUUm9NRkFjN1IzQVdaZENtbE1tdyt4WUxUVDNVZEkyaHljWGJUWU9p
dEZrQ1RZTzRwTDYySUJ0NWlubE91cDRkazBId2F6QnAwek1ZeHliNDl5MWdxaC9y
ZnBzd1RTQTdsVnp5U3lVOVNvWEFXRkhaVzRyUXJoaVh3TE9QejhjeW5yNjdsRTUv
RDV0MFhoTFRmbjVSMmVWNGs4YklwZm9TRHRNUEhtK2F6dVFudVE9PQIEQVFBQg==
-----END PUBLIC KEY-----


 */
public class RSAPublicKeyFromModulus {

    public static void main(String[] args) {
        
        
        String modulusStr = "zw_voGnxIrSEnta0BxsS4Gmr0t106iCjmIK6nciUuppcUrDTKT3t3sZLsZ5Hl-WFzkGpo9u6jWj3ul64hcpgFTRJk5xIUnbKZ20za_IRfWDTZqhZ3LqeHqBQaw0BekUzICsw6Ip1-3kg3QoQyoU973Os6MAfpOP7SafcHp_tTRoMFAc7R3AWZdCmlMmw-xYLTT3UdI2hycXbTYOitFkCTYO4pL62IBt5inlOup4dk0HwazBp0zMYxyb49y1gqh_rfpswTSA7lVzySyU9SoXAWFHZW4rQrhiXwLOPz8cynr67lE5_D5t0XhLTfn5R2eV4k8bIpfoSDtMPHm-azuQnuQ";
        String exponentStr = "AQAB";
        
        byte[] modulusBytes = base64URLDecode(modulusStr);
        byte[] exponentBytes = base64URLDecode(exponentStr);
        
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            
            PublicKey publicKey = keyFactory.generatePublic(new RSAPublicKeySpec(new BigInteger(modulusBytes), new BigInteger(exponentBytes)));
            
            X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(publicKey.getEncoded());
            
            String x509EncodedKeyStr = new String(Base64.getEncoder().encode(encodedKeySpec.getEncoded()));
            String prefix = "-----BEGIN PUBLIC KEY-----";
            String newline =  System.getProperty("line.separator") ;// "\r\n";
            String suffix = "-----END PUBLIC KEY-----";
            
            StringBuilder result =  new StringBuilder();
            // prefix + newline + x509EncodedKeyStr + newline + suffix
            result.append(prefix);
            result.append(newline);
            for(int i=0;i<x509EncodedKeyStr.length();) {
                String temp = x509EncodedKeyStr.substring(i,i+64);
                result.append(temp);
                result.append(newline);
                i = i+64;
            }
            result.append(suffix);
            
            System.out.println("X509 Public Key :");
            System.out.println(result);
            
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        
        

    }
    
    
    /**
     * <p> https://datatracker.ietf.org/doc/html/rfc7515#appendix-C </p>
     * @param base64URlEncodedString
     * @return
     */
    private static String base64URLEncode(byte[] base64URlEncodedString) {

        String tempResult = new String(base64URlEncodedString);
        tempResult = tempResult.split("=")[0];
        tempResult = tempResult.replace("+", "-");
        tempResult = tempResult.replace("_", "/");

        return tempResult;

    }
    
    
    /**
     * <p> https://datatracker.ietf.org/doc/html/rfc7515#appendix-C </p>
     * 
     * @param base64URLEncodedString
     * @return
     */
    private static byte[] base64URLDecode(String base64URLEncodedString) {

        int size = base64URLEncodedString.length();
        String tempResult = base64URLEncodedString;
        tempResult = tempResult.replace("-", "+");
        tempResult = tempResult.replace("_", "/");

        int padding = size % 4;
        switch (padding) {
        case 0:
            break;
        case 2:
            tempResult = tempResult.concat("==");
            break;
        case 3:
            tempResult = tempResult.concat("=");
            break;

        default:
            throw new IllegalArgumentException("Invalid base64urlencoded string");
        }

        return tempResult.getBytes();
    }

}
 类似资料:
  • 我一直在阅读一些RSA文献和堆栈溢出问题,但我没有得到明确的答案。 仅给定一个RSA私钥模和私钥指数,这是我所拥有的全部(也足够用于所有密码相关操作),我能得到相关的公钥模和公钥指数吗? 另外,我是否可以仅用这两个参数获得私钥的编码形式?我在java中尝试了以下方法(java不是实际的请求),但是支持它的OpenSSL引擎失败,错误为:04000090:RSA例程:openSSL_internal

  • 如果我使用getEncoded从Java中Bouncy Castle中的公钥或私钥获取实际密钥(实际类似乎是BCECPublicKey和BCECPrivateKey)。是否可以重建关键对象以在代码中使用它们? 我在Stack Overflow中发现了如何将整个对象序列化为二进制(然后序列化到磁盘),然后返回到二进制和适当类的对象,但我相信序列化包含实现细节,如果我尝试将这些键与Bouncy Cas

  • 我需要生成一个具有以下参数的JWK: > “kty”:键类型 “孩子”:密钥标识 “使用”:“sig”公钥使用 “n”:模数 “e”:“AQAB”公众指数 "x5c": X.509证书链 “x5t”:X.509证书SHA-1指纹 注: > 应包含使用“x5t”(X.509 SHA-1指纹)和“x5c”(X.509证书链)参数的X.509证书 前5个参数(kty,孩子,使用,n,e)相当简单,不是问

  • 我试图找到Java(本机或BouncyCastle提供程序)实现,以使用给定的参数{e,n,d}在PKCS#1中生成RSA私钥。 Dan Boneh的一篇论文描述了这样做的算法。PyCrypto(Python)提供了该解决方案,并且Mounir IDRASSI发布了一个独立的实用程序,用于在SFM格式(n,e,d)和CRT格式(p,q,dp,dq,u)之间转换RSA密钥,或者相反。然而,我无法找到

  • 我有一个集成,在其中验证另一个服务创建的JSON。它们提供了一个公共endpoint来获取要验证的公共证书。 但我正在为此设置一个测试,并希望与Nimbus创建相同的JWT,以使用我自己的私钥对其进行签名。所以我这样做(这是一个嵌套的加密JWT):https://connect2id.com/products/nimbus-jose-jwt/examples/signed-and-encrypte

  • 嗨,我用React和GraphQL创建了一个AWS Amplify项目。看起来Appsync提供了一个UI平台来处理GraphQL查询。我创建了graphqlapi来使用awscognitouserpool进行授权,我使用的是googlefederational登录。如何使用Cognito通过Appsync的GraphQLAPI创建的Google用户?登录模式显示clientID、userID和密