PHP RSA公钥base64编码

3

我正在开发一个网络应用程序,需要使用RSA公钥/私钥以加密方式与服务器通讯。我有一个公钥文本文件如下:

¨Ì�sr�java.math.BigIntegerå¸ü©;˚�I�bitCountIbitLengthI�firstNonzeroByteNumI�lowestSetBitI�signum[
�   magnitudet�[Bxr�java.lang.Numberܨïî‡ã��xpˇˇˇˇˇˇˇˇˇˇˇ˛ˇˇˇ˛���ur�[B¨Û¯T‡��xp���ØÕ..˛¶⁄
[í'‰∑S~ÆhU‚Ãu|ˆ*Ÿ"E˝x©àÚ†qçÎU¬òü`Oˇ?{q^⁄/O'•à%œÍ¬S� ∏íU$0≥i‹Hï™è>æ∑÷é˜ FVÚµ™ŒR=*ÑπGF%À¨ËߥÀüm‡(T¨‘Pq.ã3ˇ∑Ò;ªmÔ˙
C–„¿ç5åÌŒææ°4ån”®Å–MAQ’kÜì∑ÊË°ÂÅíîc»AÈ�
∫ıƒËv:eÚDÑØKv3Áq”cO´HÁzπ…ÅÔ©ˇwlWènö◊aAß° m͇ïöH˚Æ)˛WeŸci·JbÜ q˙H£xsq�~��ˇˇˇˇˇˇˇˇˇˇˇ˛ˇˇˇ˛���uq�~����≠íi5˛¸¥Q‚í(2ûfiΩL0ΩÅ≤ò`
÷…7¯ú)K´ºÎW2j·°Ø«¨X”gºŸ«lÇ8øÃ√3RÕ·ƒŸÚ¢fl∆,flr’X∆È|˚ì[Nfl%≈Búp·≤∑◊gπrõà–À≠˛`»Á†U„«¨ë+e|üæÄ®iLˇ⁄q¨@ä;…gRî>òvû+…U^ËÕdT∫|≠˙N"#zßø⁄+Å2ï¢=Nûe≠D˙§∞7X≥QPZ(Û`Ã-àÙ√ÿ÷Û˘£5[ŒÂ◊�IÄfiV  bf´ÄÍÚ∫ê!*Ô´õD  »E˛˙úhiô{ì“åCZWœ-åWÊ6‘t·x

当我尝试对其进行Base64编码时,结果如下:
rO0ABXNyABRqYXZhLm1hdGguQmlnSW50ZWdlcoz8nx+pO/sdAwAGSQAIYml0Q291bnRJAAliaXRMZW5ndGhJABNmaXJzdE5vbnplcm9CeXRlTnVtSQAMbG93ZXN0U2V0Qml0SQAGc2lnbnVtWwAJbWFnbml0dWRldAACW0J4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHD///////////////7////+AAAAAXVyAAJbQqzzF/gGCFTgAgAAeHAAAAEAr80ULi7+ptoVW5In5LdTfq5oVeLMdXwO9irZIkX9eKmI8qBxjetVwpifYE8M/z8ee3Fe2i9PJ6WIJQ/PHOrCUwAJA7iSVQEYAyQwF7Np3BRIlaqPPr631o73IEZW8rWqzlI9KoS5R0Yly6zop7TLn23gKFSs1FBxGi6LCjMe/7fxO7tt7/p/AUPQ48CNNYzGCu3Ovr6hNIxuBBzTqIHQTUFR1WuGk7fm6KHlgZIelAsWY8hB6QC6B3/1xALodjpl8kSErwRLdjPncdNjT6sZSOd6ucmBGu+p/3dsV49umtdhQacCocpt6uCVmkgM+64p/ldl2WMSaeFKYoYgcfpIo3hzcQB+AAD///////////////7////+AAAAAXVxAH4ABAAAAQCtDpJpDDX+Bfy0UeIXkigNMp7evQ5MML2Bsphg1sk3+JwpS6u86wdXMmrhoa/HrFjTZ7zZx2yCOL8WzMMzUh3NGuHE2fKi3xrGLN9y1VjGHul8+5NbTt8lxUKccOGytwbXZ7lym4jQEsut/h5gyOcRoFXjHceskStlfJ++gKhpTP/acaxAijvJZ1IRlD6Ydp4ryQNVXujNZFS6fK36TiJ/I3qnvxfaK4EylaISPU6eZa1E+qSwN1gQs1FQWigQ82DMLYj0w9jW8/mjNRpbEs7l1wBJgN5WCWJmqweA6vK6kCEq76ubRAnIRf76nGhpmXuT0oxDEVpXzy2MV+Y21HTheA==

每次我尝试使用该方法时,总是会出现无效的公钥。当我尝试使用以下命令时:
openssl_public_encrypt($data, $encrypted_data, base64_encode($key), OPENSSL_PKCS1_PADDING);

我知道公钥必须以以下内容开头:
-----BEGIN PUBLIC KEY-----

并以以下内容结尾:
-----END PUBLIC KEY-----

我尝试使用:

"-----BEGIN PUBLIC KEY-----\r\n" . chunk_split(base64_encode($key)) . "\r\n-----END PUBLIC KEY-----";

但它仍然无法正常工作。有人可以提供帮助吗?

4
你所谓的“文本文件中的公钥”在我看来并不是这样。只有确保这确实是密钥,你才能正确地处理它。因此,我建议你仔细检查这是否真的是一个密钥,如果是,如何从二进制文件中正确提取它。 - hakre
你能以ASCII格式获取那个密钥的副本吗?它们通常被包裹在“ASCII装甲”中,以明确密钥是什么。 - halfer
1
你所称之为“公钥”的东西看起来像是一个序列化的Java对象。显然,这种格式在PHP中不可移植。 - President James K. Polk
2
甚至不能确定那是一个公钥。它更像是一个裸的BigInteger对象。 - user149341
@duskwuff 差不多了,两个对象,模数和私钥指数。 - Maarten Bodewes
显示剩余2条评论
2个回答

2

您需要Java代码将这些序列化的BigInteger值转换为私钥和公钥。Base64编码的二进制似乎包含两个序列化的BigInteger对象,即模数和私有指数(现已公开)。要检索PEM编码,最好依赖Bouncy Castle进行转换:

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;

import org.bouncycastle.openssl.PEMWriter;
import org.bouncycastle.util.encoders.Base64;

public class KeysFromSerializedBigIntegers {

    private static final String FROM_QUESTION = "rO0ABXNyABRqYXZhLm1hdGguQmlnSW50ZWdlcoz8nx+pO/sdAwAGSQAIYml0Q291bnRJAAliaXRMZW5ndGhJABNmaXJzdE5vbnplcm9CeXRlTnVtSQAMbG93ZXN0U2V0Qml0SQAGc2lnbnVtWwAJbWFnbml0dWRldAACW0J4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHD///////////////7////+AAAAAXVyAAJbQqzzF/gGCFTgAgAAeHAAAAEAr80ULi7+ptoVW5In5LdTfq5oVeLMdXwO9irZIkX9eKmI8qBxjetVwpifYE8M/z8ee3Fe2i9PJ6WIJQ/PHOrCUwAJA7iSVQEYAyQwF7Np3BRIlaqPPr631o73IEZW8rWqzlI9KoS5R0Yly6zop7TLn23gKFSs1FBxGi6LCjMe/7fxO7tt7/p/AUPQ48CNNYzGCu3Ovr6hNIxuBBzTqIHQTUFR1WuGk7fm6KHlgZIelAsWY8hB6QC6B3/1xALodjpl8kSErwRLdjPncdNjT6sZSOd6ucmBGu+p/3dsV49umtdhQacCocpt6uCVmkgM+64p/ldl2WMSaeFKYoYgcfpIo3hzcQB+AAD///////////////7////+AAAAAXVxAH4ABAAAAQCtDpJpDDX+Bfy0UeIXkigNMp7evQ5MML2Bsphg1sk3+JwpS6u86wdXMmrhoa/HrFjTZ7zZx2yCOL8WzMMzUh3NGuHE2fKi3xrGLN9y1VjGHul8+5NbTt8lxUKccOGytwbXZ7lym4jQEsut/h5gyOcRoFXjHceskStlfJ++gKhpTP/acaxAijvJZ1IRlD6Ydp4ryQNVXujNZFS6fK36TiJ/I3qnvxfaK4EylaISPU6eZa1E+qSwN1gQs1FQWigQ82DMLYj0w9jW8/mjNRpbEs7l1wBJgN5WCWJmqweA6vK6kCEq76ubRAnIRf76nGhpmXuT0oxDEVpXzy2MV+Y21HTheA==";

    public static void main(String[] args) throws Exception {
        byte[] binary = Base64.decode(FROM_QUESTION);
        ByteArrayInputStream bais = new ByteArrayInputStream(binary);
        BufferedInputStream bis = new BufferedInputStream(bais, 16);
        ObjectInputStream ois = new ObjectInputStream(bis);

        BigInteger modulus = null;
        BigInteger privExp = null;
        while (true) {
            bis.mark(16);
            if (bis.read() == -1) {
                bis.reset();
                break;
            }
            bis.reset();

            Object o = ois.readObject();
            if (o instanceof BigInteger) {
                BigInteger bi = (BigInteger) o;

                if (modulus == null) {
                    modulus = bi;
                } else if (privExp == null) {
                    privExp = bi;
                }
            }
        }

        KeyFactory rsaKeyFactory = KeyFactory.getInstance("RSA");

        RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulus,
                privExp);
        PrivateKey privateKey = rsaKeyFactory
                .generatePrivate(rsaPrivateKeySpec);

        BigInteger guessedPubExp = BigInteger.valueOf(0x010001);
        RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(modulus,
                guessedPubExp);
        PublicKey publicKey = rsaKeyFactory.generatePublic(rsaPublicKeySpec);


        PEMWriter pemWriter = new PEMWriter(new PrintWriter(System.out));
        pemWriter.writeObject(privateKey);
        pemWriter.writeObject(publicKey);
        pemWriter.flush();

        test(privateKey, publicKey);
    }

    private static void test(PrivateKey privateKey, PublicKey publicKey)
            throws NoSuchAlgorithmException, InvalidKeyException,
            SignatureException {
        Signature rsa = Signature.getInstance("SHA512withRSA");
        rsa.initSign(privateKey);
        byte[] sig = rsa.sign();
        rsa.initVerify(publicKey);
        boolean verified = rsa.verify(sig);
        // prints true for this key pair
        System.out.println(verified);
    }
}

(注意:这甚至不符合我的代码规范)
将导致以下结果:
-----BEGIN RSA PRIVATE KEY-----
MIICHwIBAAKCAQEAr80ULi7+ptoVW5In5LdTfq5oVeLMdXwO9irZIkX9eKmI8qBx
jetVwpifYE8M/z8ee3Fe2i9PJ6WIJQ/PHOrCUwAJA7iSVQEYAyQwF7Np3BRIlaqP
Pr631o73IEZW8rWqzlI9KoS5R0Yly6zop7TLn23gKFSs1FBxGi6LCjMe/7fxO7tt
7/p/AUPQ48CNNYzGCu3Ovr6hNIxuBBzTqIHQTUFR1WuGk7fm6KHlgZIelAsWY8hB
6QC6B3/1xALodjpl8kSErwRLdjPncdNjT6sZSOd6ucmBGu+p/3dsV49umtdhQacC
ocpt6uCVmkgM+64p/ldl2WMSaeFKYoYgcfpIowIBAAKCAQEArQ6SaQw1/gX8tFHi
F5IoDTKe3r0OTDC9gbKYYNbJN/icKUurvOsHVzJq4aGvx6xY02e82cdsgji/FszD
M1IdzRrhxNnyot8axizfctVYxh7pfPuTW07fJcVCnHDhsrcG12e5cpuI0BLLrf4e
YMjnEaBV4x3HrJErZXyfvoCoaUz/2nGsQIo7yWdSEZQ+mHaeK8kDVV7ozWRUunyt
+k4ifyN6p78X2iuBMpWiEj1OnmWtRPqksDdYELNRUFooEPNgzC2I9MPY1vP5ozUa
WxLO5dcASYDeVgliZqsHgOryupAhKu+rm0QJyEX++pxoaZl7k9KMQxFaV88tjFfm
NtR04QIBAAIBAAIBAAIBAAIBAA==
-----END RSA PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr80ULi7+ptoVW5In5LdT
fq5oVeLMdXwO9irZIkX9eKmI8qBxjetVwpifYE8M/z8ee3Fe2i9PJ6WIJQ/PHOrC
UwAJA7iSVQEYAyQwF7Np3BRIlaqPPr631o73IEZW8rWqzlI9KoS5R0Yly6zop7TL
n23gKFSs1FBxGi6LCjMe/7fxO7tt7/p/AUPQ48CNNYzGCu3Ovr6hNIxuBBzTqIHQ
TUFR1WuGk7fm6KHlgZIelAsWY8hB6QC6B3/1xALodjpl8kSErwRLdjPncdNjT6sZ
SOd6ucmBGu+p/3dsV49umtdhQacCocpt6uCVmkgM+64p/ldl2WMSaeFKYoYgcfpI
owIDAQAB
-----END PUBLIC KEY-----
Verification: true

所以,这就是一个2048位的RSA密钥对,减去CRT参数。请注意,另一方至少应该使用RSAPrivateKey.getEncoded()RSAPublicKey.getEncoded()而不是对象序列化。


0

感谢您在Java中的回应,它似乎有所帮助。

然而,为了完整性和帮助任何其他可能寻找PHP解决方案的人,我想分享我的PHP解决方案。

这并不是要贬低Java答案的帮助性。

function encrypt($password, $publicKeyBase64String) {
    $publicKeyString = "-----BEGIN PUBLIC KEY-----\n" . $publicKeyBase64String . "\n-----END PUBLIC KEY-----";
    $publicKey = openssl_pkey_get_public($publicKeyString);
    openssl_public_encrypt($password, $encryptedPassword, $publicKey, OPENSSL_PKCS1_PADDING);
    return base64_encode($encryptedPassword);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接