Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
以公钥作为文本的RSA签名在java中未经验证_Java_Php_Cryptography_Digital Signature_Bouncycastle - Fatal编程技术网

以公钥作为文本的RSA签名在java中未经验证

以公钥作为文本的RSA签名在java中未经验证,java,php,cryptography,digital-signature,bouncycastle,Java,Php,Cryptography,Digital Signature,Bouncycastle,这个问题是在延续过去问题的基础上产生的。该代码适用于简单文本。但现在我需要对文本进行签名和验证,该文本的格式也有公钥(验证密钥除外) text1:text2:exported-public-key 例如: 53965C38-E950-231A-8417-074BD95744A4:22-434-565-54544:MIIBCgKCAQEAxWg6ErfkN3xu8rk9WsdzjL5GpjAucMmOAQNeZcgMBxN+VmU43EnvsDLSxUZD1e/cvfP2t2/dzhtV6N2I

这个问题是在延续过去问题的基础上产生的。该代码适用于简单文本。但现在我需要对文本进行签名和验证,该文本的格式也有公钥(验证密钥除外)

text1:text2:exported-public-key
例如:

53965C38-E950-231A-8417-074BD95744A4:22-434-565-54544:MIIBCgKCAQEAxWg6ErfkN3xu8rk9WsdzjL5GpjAucMmOAQNeZcgMBxN+VmU43EnvsDLSxUZD1e/cvfP2t2/dzhtV6N2IvT7hveuo/zm3+bUK6AnAfo6pM1Ho0z4WetoYOrHdOVNMMPaytXiVkNlXyeWRF6rl9JOe94mMYWRJzygntiD44+MXsB6agsvQmB1l8thg/8+QHNOBBU1yC4pLQwwO2cb1+oIl0svESkGpzHk8xJUl5jL6dDnhqp8+01KE7AGHwvufrsw9TfVSAPH73lwo3mBMVXE4sfXBzC0/YwZ/8pz13ToYiN88DoqzcfD3+dtrjmpoMpymAA5FBc5c6xhPRcrn24KaiwIDAQAB 
PHP代码:

$rsa = new Crypt_RSA();
$keysize=2048;
 $pubformat = "CRYPT_RSA_PUBLIC_FORMAT_PKCS1";
 $privformat = "CRYPT_RSA_PRIVATE_FORMAT_PKCS8";
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$d = $rsa->createKey($keysize);
 $Kp = $d['publickey'];
 $Ks = $d['privatekey'];

$rsa = new Crypt_RSA();
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$d = $rsa->createKey($keysize);
$Kver = $d['publickey'];
$KSign = $d['privatekey'];

$plainText = "53965C38-E950-231A-8417-074BD95744A4:22-434-565-54544:".$Kp;

// Signing
$hash = new Crypt_Hash('sha256');
$rsa = new Crypt_RSA();    
$rsa->loadKey($KSign);
$rsa->setSignatureMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setHash('sha256');

$signature = $rsa->sign($plainText);
$signedHS = base64_encode($signature);

// Verification

$signature = base64_decode($signedHS);
$rsa->loadKey($Kver);
$status = $rsa->verify($plainText, $signature);

var_dump($status);        
JAVA代码

import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.math.BigInteger;
import java.security.spec.X509EncodedKeySpec;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
//import java.util.Base64;
//import java.util.Base64.Decoder;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class VerifySig {

    public static RSAPublicKey fromPKCS1Encoding(byte[] pkcs1EncodedPublicKey) {
        // --- parse public key ---
        org.bouncycastle.asn1.pkcs.RSAPublicKey pkcs1PublicKey;
        try {
            pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey
                    .getInstance(pkcs1EncodedPublicKey);
        } catch (Exception e) {
            throw new IllegalArgumentException(
                    "Could not parse BER PKCS#1 public key structure", e);
        }

        // --- convert to JCE RSAPublicKey
        RSAPublicKeySpec spec = new RSAPublicKeySpec(
                pkcs1PublicKey.getModulus(), pkcs1PublicKey.getPublicExponent());
        KeyFactory rsaKeyFact;
        try {
            rsaKeyFact = KeyFactory.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("RSA KeyFactory should be available", e);
        }
        try {
            return (RSAPublicKey) rsaKeyFact.generatePublic(spec);
        } catch (InvalidKeySpecException e) {
            throw new IllegalArgumentException(
                    "Invalid RSA public key, modulus and/or exponent invalid", e);
        }
    }


    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        String pkey = "MIIBCgKCAQEA+8fKYCT4QiFUdsJ7VdF4xCkVmq/Kwc/10Jl3ie6mvn8hEsC3NAtMJu+Od12gyWYsS0zBDiQ8h2pGZ7p4uWqenc01dRRrq+g968zmoCKPUllPUuR6v9o+wYTX/os4hgaQSBg7DQn4g3BEekcvyk6e6zAMvuhHjeqnrinhCMFgJUhFL8zFNoyaH559C0TNbR6BTKzOoikah8cKhu4UOga0tWDC0I2Ifus/sHOwVaOBkDFIzD6jBxDH/QF8FsrLLTocuIb7Y6lVxFPPtgiUJku6b7wKExV0bPJvm6/Xhv1GX1FpMrA0Ylzj5IFviuviwgo534EcZQ/Hx3aIf4oPG8jVTQIDAQAB";
        byte[] dpkey = Base64.decodeBase64(pkey);
        RSAPublicKey publicKey = fromPKCS1Encoding(dpkey);
        String plainData = "53965C38-E950-231A-8417-074BD95744A4:22-434-565-54544:MIIBCgKCAQEArszIunGg3ievJOpgesYQsp3nPGgrW+3VwkivkkktOXUBRzb3G3mZzidEjG6LxNe/rrNe0UczmnSHQoSBxJCHyUnCWNfScBD66CFG4hLo5Z1gxrP8D2M2lCa6ap2PWcsKiWqlu38EinMeBjBvB4aYpF7+FkFy64ObxR4pfVZxnxradkD0HvvMPLMbyeHxeGqYf8orERf9jfuKTdY8V44rxht2D2fg2WhB1+XL0JulsPvgOaSK3RPnwi+RQAJbihCIh5Zznn0KQCs5pIWoT3XKe1DMpQuEmphSOY9ZUg3AwlOrpRV+565x6GCSc615/6nowmqKzE4T7qT5nbH+ctiEHQIDAQAB";
        String data = "iD96rNeR51BF2TUZSaw+QhW8SnsMXE5AdJiDVmJk6LL55jC26PBCnqXrFo2lsQt8aWRsZc0bHFGCcuIbhHA+Duo1/PwrxTqC5BZFL/frqsRSVa+vpvGEnj3xe4iImTEasMicQzzaAG9IWIgkRZ272lUZ8PqdtTuqAsRIwir6fEsfVs5uIErEWM18R4JxlFBc3LDIjFOFemEPSVIEBHwWht1c/CrdTtxPRIiugEb1jdofEBUNcWPZgfvApVx5+0aS9WTl31AY+RMlvp+13P/FQgAMnH9rvBdopRIVsZUNlMf8AOE2afhLPfOgx+41rzCB2wGCrRGELbml466WJ3wYNQ==";
        byte[] ciphertext = Base64.decodeBase64(data);
        System.out.println(new String(plainData.getBytes(), UTF_8));
        verifyBC(publicKey, plainData, ciphertext);
        System.out.flush();
    }

    private static void verifyBC(PublicKey publicKey, String plainData,
            byte[] ciphertext) throws Exception {
        // what should work (for PKCS#1 v1.5 signatures), requires Bouncy Castle provider
        //Signature sig = Signature.getInstance( "SHA256withRSAandMGF1");
        Signature sig = Signature.getInstance( "SHA256withRSA");
        sig.initVerify(publicKey);
        sig.update(plainData.getBytes(UTF_8));
        System.out.println(sig.verify(ciphertext));
    }
}
在明文中使用公钥时,它没有给出任何错误,只返回false。如果在使用公钥删除后重试,它将工作并返回true

PHP工作正常,签名在所有情况下都经过验证

我怀疑java是否无法验证以Base64文本/公钥作为文本的数据

更新:我比较了两次二进制字节,结果显示了微小的差异

第一例

  • PHP->��#C:���平方英尺
  • JAVA->��/#C:���平方英尺
  • 第二种情况

  • PHP->��]Q0l�O+
  • JAVA->��]Q0l�
    如果php base64与apache base 64不兼容?

    当我运行php代码时,我注意到
    $Kp
    变量包含一个格式错误的键:

    -----BEGIN RSA PUBLIC KEY-----
    MIIBCgKCAQEAqCJ/2E+YZvXJyabQmi0zZlaXXGbfXHt8KYS27i+PAJKBODmevTrS
    w59S5AOy2l7lB4z5mYHuwdT6bm6YYXgE0gnoX/b2L65xdD9XtlenS4Zm15TVTdR5
    zde4nBa0QPKfhFvthOmdPr9xDhDb8Rojy/phX+Ftva33ceTXoB+CtLyidMWbQmUh
    ZufnI7MwIOPAIzXNJJ85eyUjBdoNMwlAPZo9vYQWeiwYGyP1fjQwEWZgjCH/LJjl
    sNR1X9vp5oi8/4omdnFRvKLpkd5R7WMmMfAyAXe7tcfMSXuVAgMWEj9ZG0ELpXbG
    S3CK6nvOp2gFF+AjHo9bCrh397jYotE3HQIDAQAB
    -----END RSA PUBLIC KEY-----
    
    当我去掉所有额外的格式并将密钥导出为一行base64时,它就可以工作了

    PHP代码:

    function extract_key($pkcs1) {
        # strip out -----BEGIN/END RSA PUBLIC KEY-----, line endings, etc
        $temp = preg_replace('#.*?^-+[^-]+-+#ms', '', $pkcs1, 1);
            $temp = preg_replace('#-+[^-]+-+#', '', $temp);
            return str_replace(array("\r", "\n", ' '), '', $temp);
    }
    
    $rsa = new Crypt_RSA();
    $keysize=2048;
     $pubformat = "CRYPT_RSA_PUBLIC_FORMAT_PKCS1";
     $privformat = "CRYPT_RSA_PRIVATE_FORMAT_PKCS8";
    $rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
    $rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
    $d = $rsa->createKey($keysize);
     $Kp = $d['publickey'];
     $Ks = $d['privatekey'];
    
    
    $rsa = new Crypt_RSA();
    $rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
    $rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
    $d = $rsa->createKey($keysize);
    $Kver = $d['publickey'];
    $KSign = $d['privatekey'];
    
    file_put_contents("pub_verify_key.txt",extract_key($Kver));
    
    $plainText = "53965C38-E950-231A-8417-074BD95744A4:22-434-565-54544:".extract_key($Kp);
    
    file_put_contents("plain.txt",$plainText);
    
    // Signing
    $hash = new Crypt_Hash('sha256');
    $rsa = new Crypt_RSA();    
    $rsa->loadKey($KSign);
    $rsa->setSignatureMode(CRYPT_RSA_ENCRYPTION_PKCS1);
    $rsa->setHash('sha256');
    
    $signature = $rsa->sign($plainText);
    
    $signedHS = base64_encode($signature);
    
    file_put_contents("signedkey.txt", $signedHS);
    
    // Verification
    
    $signature = base64_decode($signedHS);
    $rsa->loadKey($Kver);
    $status = $rsa->verify($plainText, $signature);
    
    var_dump($status);
    
    Java代码:

    import static java.nio.charset.StandardCharsets.UTF_8;
    import java.io.ByteArrayOutputStream;
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    import java.io.ObjectInputStream;
    import java.io.File;
    import java.io.FileReader;
    import java.math.BigInteger;
    import java.security.spec.X509EncodedKeySpec;
    import java.security.KeyFactory;
    import java.security.NoSuchAlgorithmException;
    import java.security.PublicKey;
    import java.security.Security;
    import java.security.Signature;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.RSAPublicKeySpec;
    import org.apache.commons.codec.binary.Base64;
    
    import javax.crypto.Cipher;
    
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    
    public class VerifySig {
    
        public static RSAPublicKey fromPKCS1Encoding(byte[] pkcs1EncodedPublicKey) {
            // --- parse public key ---
            org.bouncycastle.asn1.pkcs.RSAPublicKey pkcs1PublicKey;
            try {
                pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey
                        .getInstance(pkcs1EncodedPublicKey);
            } catch (Exception e) {
                throw new IllegalArgumentException(
                        "Could not parse BER PKCS#1 public key structure", e);
            }
    
            // --- convert to JCE RSAPublicKey
            RSAPublicKeySpec spec = new RSAPublicKeySpec(
                    pkcs1PublicKey.getModulus(), pkcs1PublicKey.getPublicExponent());
            KeyFactory rsaKeyFact;
            try {
                rsaKeyFact = KeyFactory.getInstance("RSA");
            } catch (NoSuchAlgorithmException e) {
                throw new IllegalStateException("RSA KeyFactory should be available", e);
            }
            try {
                return (RSAPublicKey) rsaKeyFact.generatePublic(spec);
            } catch (InvalidKeySpecException e) {
                throw new IllegalArgumentException(
                        "Invalid RSA public key, modulus and/or exponent invalid", e);
            }
        }
    
    
        public static void main(String[] args) throws Exception {
            Security.addProvider(new BouncyCastleProvider());
    
        String pkey = fromFile("pub_verify_key.txt");
            byte[] dpkey = Base64.decodeBase64(pkey);
            RSAPublicKey publicKey = fromPKCS1Encoding(dpkey);
            String plainData = fromFile("plain.txt");
            String data = fromFile("signedkey.txt");
            byte[] ciphertext = Base64.decodeBase64(data);
            System.out.println(new String(plainData.getBytes(), UTF_8));
            verifyBC(publicKey, plainData, ciphertext);
            System.out.flush();
        }
    
        private static void verifyBC(PublicKey publicKey, String plainData,
                byte[] ciphertext) throws Exception {
            // what should work (for PKCS#1 v1.5 signatures), requires Bouncy Castle provider
            //Signature sig = Signature.getInstance( "SHA256withRSAandMGF1");
            Signature sig = Signature.getInstance( "SHA256withRSA");
            sig.initVerify(publicKey);
            sig.update(plainData.getBytes(UTF_8));
            System.out.println(sig.verify(ciphertext));
        }
    
        private static String fromFile(String filename) {
            StringBuilder builder = new StringBuilder(8000);
            try {
                FileReader reader = new FileReader(new File(filename));
                int c;
                while((c = reader.read()) != -1) {
                    builder.append((char)c);
                }
            } catch(IOException ioe) {
                throw new RuntimeException(ioe);
            }
            return builder.toString();
        }
    }
    

    在PHP代码中,公钥的编码基于哪里?或者公钥是否自动编码为base 64?@MaartenBodewes,是公钥/私钥由库自动编码。这是可导出文件的版本。您应该尝试对签名生成函数的输入进行二进制比较。这可能很简单,比如不同的行尾。请在base 64之前签出字节,并将它们与两种不同的大小写进行比较,每种大小写都有细微的差异。我在调试您的问题时遇到了一些困难,因为我没有您用于生成该签名的密钥。然而,当我运行PHP代码时,我注意到$Kp包含一个封装在--BEGIN/END RSA公钥-----中的密钥。当我使用PHP脚本将密钥导出为base64行时,它可以工作。看见