V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
kangsgo
V2EX  ›  Java

请问一下这个 RSA 密钥经过了怎么处理呀

  •  
  •   kangsgo · 2021-10-10 17:15:13 +08:00 · 2053 次点击
    这是一个创建于 919 天前的主题,其中的信息可能已经有所发展或是发生改变。

    他给了我一个测试公钥

    MIGAMA0GCSqGSIb3DQEBAQUAA28AMGwCZQCeh0LCZFTcyDINybUavJb-d0sMTMv5-xGDcGmJq38cwtij3n-bFl_qpX2lgN516bGnqZC0-kt-RkmWitXSNj-1yLu4hg1SNy-HfHuvFWulDLpDgt-JOflfCH9cMUZxbOWhf6IlAgMBAAE
    

    不知道经过了什么,我用 php 怎么都读不了这个公钥

    下面是文档里面给的 java demo,一直转不成 php 版本的

    package com.xxtx.common.util;
    
    import org.apache.commons.codec.binary.Base64;
    import org.apache.commons.io.IOUtils;
    
    import javax.crypto.Cipher;
    import java.io.ByteArrayOutputStream;
    import java.security.*;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.HashMap;
    import java.util.Map;
    
    
    public class RSAUtils {
    public static final String CHARSET = "UTF-8";
        public static final String RSA_ALGORITHM = "RSA"; // ALGORITHM ['?lg?r??(?)m] 算法的意思
    
    public static Map<String, String>createKeys(int keySize) {
    // 为 RSA 算法创建一个 KeyPairGenerator 对象
    KeyPairGenerator kpg;
            try {
                kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);
    } catch (NoSuchAlgorithmException e) {
    throw new IllegalArgumentException("No such algorithm-->["+ RSA_ALGORITHM + "]");
    }
    
    // 初始化 KeyPairGenerator 对象,密钥长度
    kpg.initialize(keySize);
    // 生成密匙对
    KeyPair keyPair = kpg.generateKeyPair();
    // 得到公钥
    Key publicKey = keyPair.getPublic();
    String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded());
    // 得到私钥
    Key privateKey = keyPair.getPrivate();
    String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded());
    // map 装载公钥和私钥
    Map<String, String> keyPairMap = new HashMap<String, String>();
    keyPairMap.put("publicKey", publicKeyStr);
    keyPairMap.put("privateKey", privateKeyStr);
    // 返回 map
    return keyPairMap;
    }
    
    /**
         * 得到公钥
    * @param publicKey  密钥字符串(经过 base64 编码)
    * @throws Exception
         */
    public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    // 通过 X509 编码的 Key 指令获得公钥对象
    KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
    RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
            return key;
    }
    
    /**
         * 得到私钥
    * @param privateKey  密钥字符串(经过 base64 编码)
    * @throws Exception
         */
    public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    // 通过 PKCS#8 编码的 Key 指令获得私钥对象
    KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
    RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
            return key;
    }
    
    /**
         * 公钥加密
    * @param data
    * @param publicKey
    * @return
    */
    public static String publicEncrypt(String data, RSAPublicKey publicKey) {
    try {
                Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
                return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength()));
    } catch (Exception e) {
    throw new RuntimeException("加密字符串["+ data + "]时遇到异常", e);
    }
        }
    
    /**
         * 私钥解密
    * @param data
    * @param privateKey
    * @return
    */
    
    public static String privateDecrypt(String data, RSAPrivateKey privateKey) {
    try {
                Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
                return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), CHARSET);
    } catch (Exception e) {
    throw new RuntimeException("解密字符串["+ data + "]时遇到异常", e);
    }
        }
    
    /**
         * 私钥加密
    * @param data
    * @param privateKey
    * @return
    */
    
    public static String privateEncrypt(String data, RSAPrivateKey privateKey) {
    try {
                Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
    //每个 Cipher 初始化方法使用一个模式参数 opmod,并用此模式初始化 Cipher 对象。此外还有其他参数,包括密钥 key 、包含密钥的证书 certificate 、算法参数 params 和随机源 random 。
    cipher.init(Cipher.ENCRYPT_MODE, privateKey);
                return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus().bitLength()));
    } catch (Exception e) {
    throw new RuntimeException("加密字符串["+ data + "]时遇到异常", e);
    }
        }
    
    /**
         * 公钥解密
    * @param data
    * @param publicKey
    * @return
    */
    
    public static String publicDecrypt(String data, RSAPublicKey publicKey) {
    try {
                Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
    cipher.init(Cipher.DECRYPT_MODE, publicKey);
                return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), CHARSET);
    } catch (Exception e) {
    throw new RuntimeException("解密字符串["+ data + "]时遇到异常", e);
    }
        }
    
    //rsa 切割解码  , ENCRYPT_MODE,加密数据   ,DECRYPT_MODE,解密数据
    private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) {
    int maxBlock = 0;  //最大块
    if (opmode == Cipher.DECRYPT_MODE) {
                maxBlock = keySize / 8;
    } else {
                maxBlock = keySize / 8 - 11;
    }
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] buff;
            int i = 0;
            try {
    while (datas.length > offSet) {
    if (datas.length - offSet > maxBlock) {
    //可以调用以下的 doFinal ()方法完成加密或解密数据:
    buff = cipher.doFinal(datas, offSet, maxBlock);
    } else {
                        buff = cipher.doFinal(datas, offSet, datas.length - offSet);
    }
                    out.write(buff, 0, buff.length);
    i++;
    offSet = i * maxBlock;
    }
            } catch (Exception e) {
    throw new RuntimeException("加解密阀值为["+ maxBlock + "]的数据时发生异常", e);
    }
    byte[] resultDatas = out.toByteArray();
    IOUtils.closeQuietly(out);
            return resultDatas;
    }
    
    
    }
    
    10 条回复    2021-10-11 11:08:42 +08:00
    kangsgo
        1
    kangsgo  
    OP
       2021-10-10 17:16:53 +08:00
    我试了一下 base64 解密这个公钥,好像也解密不出来
    sujin190
        2
    sujin190  
       2021-10-10 18:25:00 +08:00
    自己组一下 pem 文件格式呗,网上查一下就有吧,php 好像读取的是这种格式吧,确实是不需要自己解码 base64 的
    kangsgo
        4
    kangsgo  
    OP
       2021-10-10 18:41:25 +08:00
    @sujin190 他给的公钥是处理过的,不知道处理了哪里,php 读不出来
    kangsgo
        5
    kangsgo  
    OP
       2021-10-10 18:43:27 +08:00
    @keyfunc 您好,请问方便多指导一下么,这个做的公钥还是没法加密,我用的这个在线加密的
    https://www.bejson.com/enc/rsa/
    eason1874
        6
    eason1874  
       2021-10-10 18:46:50 +08:00   ❤️ 2
    因为这个不是标准的 base64,需要先转换成标准 base64,看你这么久没解决,给你写个例子

    ```
    <?php
    $str = 'MIGAMA0GCSqGSIb3DQEBAQUAA28AMGwCZQCeh0LCZFTcyDINybUavJb-d0sMTMv5-xGDcGmJq38cwtij3n-bFl_qpX2lgN516bGnqZC0-kt-RkmWitXSNj-1yLu4hg1SNy-HfHuvFWulDLpDgt-JOflfCH9cMUZxbOWhf6IlAgMBAAE';

    function urlsafe_b64decode($string) {
    $data = str_replace(array('-','_'),array('+','/'),$string);
    $mod4 = strlen($data) % 4;
    if ($mod4) {
    $data .= substr('====', $mod4);
    }
    return base64_decode($data);
    }

    // 转为标准 base64
    $str = urlsafe_b64decode($str);

    // 封装
    $pub_key = "-----BEGIN PUBLIC KEY-----\n" . base64_encode($str) . "\n-----END PUBLIC KEY-----";

    // 解析证书,用于后续加解密等操作
    $pub_key_res = openssl_get_publickey($pub_key);

    // 读取证书信息
    var_dump(openssl_pkey_get_details($pub_key_res));

    // 加密例子,输出 base64 格式
    openssl_public_encrypt("hello", $crypttext, $pub_key);
    var_dump(base64_encode($crypttext));

    ```
    sarvatathagata
        7
    sarvatathagata  
       2021-10-10 18:49:29 +08:00
    这代码挺有意思的啊

    "// ALGORITHM ['?lg?r??(?)m] 算法的意思"
    “阀值”
    eason1874
        8
    eason1874  
       2021-10-10 18:56:15 +08:00   ❤️ 2
    顺便一提,处理 base64 内容,第一件事先看格式对不对,很多接受 base64 格式的输入只能接受标准 base64

    标准 base64 只有 + / = 三个符号,有 - _ 这种符号的是 base64 变体,通常用来兼容 URL,因为默认符号作为网址时被转义
    kangsgo
        9
    kangsgo  
    OP
       2021-10-11 10:04:25 +08:00
    @eason1874 谢谢大佬,能否给个联系方式,不问问题哈,仅发红包表示感谢
    eason1874
        10
    eason1874  
       2021-10-11 11:08:42 +08:00
    @kangsgo 不了,别客气。我是电脑摸鱼,方便,写个例子就几分钟的事。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1356 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 23:40 · PVG 07:40 · LAX 16:40 · JFK 19:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.