首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用公钥加密消息: BER解码错误

用公钥加密消息: BER解码错误
EN

Stack Overflow用户
提问于 2020-01-24 10:15:22
回答 2查看 435关注 0票数 0

关于使用公钥加密消息,我有一个问题。我想用一个包含在字符串中的公钥RSA-4096加密一个字符串(比如"test")。让我们说:

-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAm9GgFeJ3DhazIHCVHtNa Vnu38KBdxViOswyXcJEwQ8yHlQOL6e5He1dxx5uqvnKLR7+gAMzZBXEQlOCrSYi6 nREXGxE4WFTjd+PqLh5bA9DIO8vbsPIsG66zYmFdztmFGn2dl0EUvUiIjGUqwkJA E5P8ebjsNOdomX1763p8k50AHhIzaUbD+IWAVDEzbew7efOPt5Wj6C5a1kwkv4bX +viqoC7mFNjQziI+Sg/8yjnT++Zv5fo+JWE6pyXwZCabwgsBYq9Cv2iMC4ZXAFVo GLYtixok/7rMY6NIe+MIUafrEVbgG8K0YT3U1Jn1knqYV++qtnaqqmcvtoGC1SE6 s8pwiHGRgh+ZG3EwuDZVqJadBdl/CGDz8WnfPs8sSANT1kCJYq3ogp12Fx0axENF vklCM5jLcm1v6/kyqPYk0fVArH6RT7e5QZCWZXAoxMz1bZe97CZ9+PQGbGLyYrQO CqBeWkVUEI/NeBoQdifrgok/Ku43LMUrxbTByBSEoXVn4d+3jgN0BS1CmxQslJml kUPv87OLjzzggQW8lRs3owKQF9TRs9fYljuJSt3f2osYaPhedYx9XdkJNhgbH+AF 47kocpxg6olpOtRaM5cW/0zWSGtVHXfblDO+XFNzddSKLwFyL2Jx8WIfZ6tXa/MP /aLOyzKX/WADqAEqlHbs3SMCAwEAAQ== -----END PUBLIC KEY-----

为此,我尝试使用CryptoPP库在C++ (https://www.cryptopp.com/wiki/Keys_and_formats),但当我试图读取和解码我的公钥,我得到以下错误:BER decode error。下面是我使用的完整源代码:

代码语言:javascript
复制
#include <string>
#include <iomanip> 
#include <iostream>
#include <exception>
#include <fstream>

#include <cryptopp/queue.h>
using CryptoPP::ByteQueue;

#include <cryptopp/filters.h>
using CryptoPP::Redirector;

#include <cryptopp/files.h>
using CryptoPP::FileSource;
using CryptoPP::FileSink;

#include <cryptopp/cryptlib.h>
using CryptoPP::PrivateKey;
using CryptoPP::PublicKey;
using CryptoPP::BufferedTransformation;

#include <cryptopp/sha.h>
#include <cryptopp/rsa.h>
using CryptoPP::RSA;

#include <cryptopp/base64.h>
using CryptoPP::Base64Encoder;
using CryptoPP::Base64Decoder;

#include <cryptopp/osrng.h>
using CryptoPP::AutoSeededRandomPool;

using namespace std;

int main(int argc, char** argv) {

    ByteQueue queue;

    string RSA_PUBLIC_KEY ="-----BEGIN PUBLIC KEY-----MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAm9GgFeJ3DhazIHCVHtNaVnu38KBdxViOswyXcJEwQ8yHlQOL6e5He1dxx5uqvnKLR7+gAMzZBXEQlOCrSYi6nREXGxE4WFTjd+PqLh5bA9DIO8vbsPIsG66zYmFdztmFGn2dl0EUvUiIjGUqwkJAE5P8ebjsNOdomX1763p8k50AHhIzaUbD+IWAVDEzbew7efOPt5Wj6C5a1kwkv4bX+viqoC7mFNjQziI+Sg/8yjnT++Zv5fo+JWE6pyXwZCabwgsBYq9Cv2iMC4ZXAFVoGLYtixok/7rMY6NIe+MIUafrEVbgG8K0YT3U1Jn1knqYV++qtnaqqmcvtoGC1SE6s8pwiHGRgh+ZG3EwuDZVqJadBdl/CGDz8WnfPs8sSANT1kCJYq3ogp12Fx0axENFvklCM5jLcm1v6/kyqPYk0fVArH6RT7e5QZCWZXAoxMz1bZe97CZ9+PQGbGLyYrQOCqBeWkVUEI/NeBoQdifrgok/Ku43LMUrxbTByBSEoXVn4d+3jgN0BS1CmxQslJmlkUPv87OLjzzggQW8lRs3owKQF9TRs9fYljuJSt3f2osYaPhedYx9XdkJNhgbH+AF47kocpxg6olpOtRaM5cW/0zWSGtVHXfblDO+XFNzddSKLwFyL2Jx8WIfZ6tXa/MP/aLOyzKX/WADqAEqlHbs3SMCAwEAAQ==-----END PUBLIC KEY-----";
    static string HEADER = "-----BEGIN PUBLIC KEY-----";
    static string FOOTER = "-----END PUBLIC KEY-----";

    size_t pos1 = RSA_PUBLIC_KEY.find(HEADER);
    if(pos1 == string::npos) throw runtime_error("PEM header not found");

    size_t pos2 = RSA_PUBLIC_KEY.find(FOOTER, pos1+1);
    if(pos2 == string::npos) throw runtime_error("PEM footer not found");

    // Start position and length
    pos1 = pos1 + HEADER.length();
    pos2 = pos2 - pos1;

    string keystr = RSA_PUBLIC_KEY.substr(pos1, pos2);    
    /*Base64Encoder decoder;
    decoder.Attach(new Redirector(queue));*/
    queue.Put((const byte*)keystr.data(), keystr.length());
    queue.MessageEnd();

    cout << keystr << endl;

    try {

        RSA::PublicKey public_key;
        public_key.BERDecodePublicKey(queue, false /*paramsPresent*/, queue.MaxRetrievable());

        if(queue.IsEmpty()) {
            cerr << "The queue is empty...";
        }

        AutoSeededRandomPool prng;
        bool valid = public_key.Validate(prng, 3);
        if(!valid) cerr << "RSA public key is not valid" << endl;

        cout << "N:" << public_key.GetModulus() << endl;
        cout << "E:" << public_key.GetPublicExponent() << endl;

    } catch (exception& e) {

        printf( "Caught exception: %s\n", e.what() );
        exit (1);
    } 
}

非常感谢那些能帮助我理解为什么公钥不能正确阅读的人。对于那些讲golang的人,我基本上是在尝试再现以下功能:

代码语言:javascript
复制
func WriteEncryptedWithPublicKeyInformation(filename string, information string, publicKey string) error {

    f, err := os.Create(filename)

    block, _ := pem.Decode([]byte(publicKey))
    if block == nil {
        return errors.New("Failed to parse PEM block containing the public key")
    }

    pub, err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
        return errors.New("Failed to parse DER encoded public key: " + err.Error())
    }

    key := pub.(*(rsa.PublicKey))
    ciphertext, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, key, []byte(information), nil)
    if err != nil {
        return err
    }

    _, err = f.WriteString(b64.StdEncoding.EncodeToString(ciphertext))
    if err != nil {
        return err

    }
    f.Close()
    return nil
}

其中filename是我的输出文件,information是我要加密的字符串,publicKey是包含公钥的字符串。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-24 15:43:28

您的程序解码base64的方式是不正确的,根据引用函数RSAFunction::BERDecodePublicKey是不正确的。

BERDecodePublicKey()对subjectPublicKeyInfo的subjectPublicKey部分进行解码,而不使用位字符串头。

您应该使用X509PublicKey::BERDecode函数,因为类RSA::PublicKey继承自X509PublicKey

试试这个程序,它应该能工作。

代码语言:javascript
复制
#include <string>
#include <iomanip>
#include <iostream>
#include <exception>
#include <fstream>


#include <cryptopp/queue.h>
using CryptoPP::ByteQueue;

#include <cryptopp/filters.h>
using CryptoPP::Redirector;

#include <cryptopp/files.h>
using CryptoPP::FileSource;
using CryptoPP::FileSink;

#include <cryptopp/cryptlib.h>
using CryptoPP::PrivateKey;
using CryptoPP::PublicKey;
using CryptoPP::BufferedTransformation;

#include <cryptopp/sha.h>
#include <cryptopp/rsa.h>
#include <cryptopp/asn.h>

using CryptoPP::RSA;

#include <cryptopp/base64.h>
using CryptoPP::Base64Encoder;
using CryptoPP::Base64Decoder;

#include <cryptopp/osrng.h>
using CryptoPP::AutoSeededRandomPool;

using namespace std;

int main() {

    ByteQueue queue;

    string RSA_PUBLIC_KEY ="-----BEGIN PUBLIC KEY-----MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAm9GgFeJ3DhazIHCVHtNaVnu38KBdxViOswyXcJEwQ8yHlQOL6e5He1dxx5uqvnKLR7+gAMzZBXEQlOCrSYi6nREXGxE4WFTjd+PqLh5bA9DIO8vbsPIsG66zYmFdztmFGn2dl0EUvUiIjGUqwkJAE5P8ebjsNOdomX1763p8k50AHhIzaUbD+IWAVDEzbew7efOPt5Wj6C5a1kwkv4bX+viqoC7mFNjQziI+Sg/8yjnT++Zv5fo+JWE6pyXwZCabwgsBYq9Cv2iMC4ZXAFVoGLYtixok/7rMY6NIe+MIUafrEVbgG8K0YT3U1Jn1knqYV++qtnaqqmcvtoGC1SE6s8pwiHGRgh+ZG3EwuDZVqJadBdl/CGDz8WnfPs8sSANT1kCJYq3ogp12Fx0axENFvklCM5jLcm1v6/kyqPYk0fVArH6RT7e5QZCWZXAoxMz1bZe97CZ9+PQGbGLyYrQOCqBeWkVUEI/NeBoQdifrgok/Ku43LMUrxbTByBSEoXVn4d+3jgN0BS1CmxQslJmlkUPv87OLjzzggQW8lRs3owKQF9TRs9fYljuJSt3f2osYaPhedYx9XdkJNhgbH+AF47kocpxg6olpOtRaM5cW/0zWSGtVHXfblDO+XFNzddSKLwFyL2Jx8WIfZ6tXa/MP/aLOyzKX/WADqAEqlHbs3SMCAwEAAQ==-----END PUBLIC KEY-----";
    static string HEADER = "-----BEGIN PUBLIC KEY-----";
    static string FOOTER = "-----END PUBLIC KEY-----";

    size_t pos1 = RSA_PUBLIC_KEY.find(HEADER);
    if(pos1 == string::npos) throw runtime_error("PEM header not found");

    size_t pos2 = RSA_PUBLIC_KEY.find(FOOTER, pos1+1);
    if(pos2 == string::npos) throw runtime_error("PEM footer not found");

    // Start position and length
    pos1 = pos1 + HEADER.length();
    pos2 = pos2 - pos1;

    string keystr = RSA_PUBLIC_KEY.substr(pos1, pos2);

    CryptoPP::StringSource ss{keystr.c_str(), true};

    Base64Decoder decoder;
    decoder.Attach(new Redirector(queue));
    ss.TransferTo(decoder);
    decoder.MessageEnd();

    cout << keystr << endl;

    try {

        RSA::PublicKey public_key;

        if(queue.IsEmpty()) {
            cerr << "The queue is empty...";
        }

        public_key.BERDecode(queue);

        AutoSeededRandomPool prng;
        bool valid = public_key.Validate(prng, 3);
        if(!valid) cerr << "RSA public key is not valid" << endl;

        cout << "N:" << public_key.GetModulus() << endl;
        cout << "E:" << public_key.GetPublicExponent() << endl;

    } catch (exception& e) {

        printf( "Caught exception: %s\n", e.what() );
        exit (1);
    }
}
票数 2
EN

Stack Overflow用户

发布于 2020-01-24 14:49:41

我没看到你在中间破解基地64。BER是一种二进制格式,您首先必须转换为二进制才能读取它。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59894378

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档