rust RSA私有解密填充

b4lqfgs4  于 2023-02-19  发布在  其他
关注(0)|答案(1)|浏览(201)

我用Python中的cryptography库用公钥加密一个密钥。

key_path = "key.bin"
key = secrets.token_bytes(32)
with open(key_path, "w") as key_file:
    key_file.write(key.hex())

with open(public_key, "rb") as public_key_file:
    public_key = serialization.load_pem_public_key(public_key_file.read())

padding_config = padding.OAEP(
    mgf=padding.MGF1(algorithm=hashes.SHA256()),
    algorithm=hashes.SHA256(),
    label=None
)

enc_path = key_path + ".enc"
with open(enc_path, "wb") as enc_file:
    bytes_array = public_key.encrypt(content, padding_config)
    enc_file.write(bytes_array)

这很好用,但是阅读这个键的代码是在Rust中,它只是一个对openssl C调用的FFI。openssl没有太多的选项。你不能选择“algorithm”,“mgf”和“label”。填充只是一个枚举,所以我选择了显而易见的PKCS1_OAEP

use openssl::{
    cipher::Cipher,
    cipher_ctx::CipherCtx,
    pkey::Private,
    rsa::{Padding, Rsa},
};

pub fn decrypt(key_file: File, pk: &str, pass: &str) -> String {
    let rsa = Rsa::private_key_from_pem_passphrase(pk.as_bytes(), pass.as_bytes())
        .expect("Can't build RSA object from PEM");
    let mut encrypted = vec![];
    key_file.read_to_end(&mut encrypted).expect("Can't read encrypted key file");
    let mut decrypted: Vec<u8> = vec![0; rsa.size() as usize];
    rsa.private_decrypt(&encrypted, &mut decrypted, Padding::PKCS1_OAEP).unwrap();
    String::from_utf8(decrypted)
}

但我得到这个错误:

ErrorStack([
    Error { code: 67571871, library: "rsa routines", function: "RSA_padding_check_PKCS1_type_2", reason: "pkcs decoding error", file: "../crypto/rsa/rsa_pk1.c", line: 251 },
    Error { code: 67522674, library: "rsa routines", function: "rsa_ossl_private_decrypt", reason: "padding check failed", file: "../crypto/rsa/rsa_ossl.c", line: 500 }
])

我知道Rust代码是“正确的”,因为在以前的版本中,当我使用子进程调用openssl而不是cryptography库时,它工作得很好(与Padding::PKCS1一起)。
openssl documentation告诉我
RSA_PKCS1_OAEP_填充
PKCS #1 v2.0中定义的EME-OAEP,带有SHA-1、MGF 1和空编码参数。建议所有新应用程序使用此模式。
但是使用hashes.SHA1()并没有改变任何东西。我应该如何设置我的padding以便openssl接受解密呢?

9udxz4iz

9udxz4iz1#

据推测,发布的Rust代码使用RFC 8017默认值作为OAEP参数,即SHA-1作为内容摘要和MGF 1摘要,以及一个空标签。
另一方面,发布的Python代码对两个摘要都使用SHA-256,这就是为什么这两个代码不兼容的原因,你必须在Rust端将两个摘要都设置为SHA-256(或者你可以在Python端使用SHA-1)。
在这里,您可以找到一个用于OAEP的Rust sample implementation。OAEP填充的设置是使用set_rsa_padding(Padding::PKCS1_OAEP)完成的。要避免使用SHA-1默认值作为内容摘要,必须使用set_rsa_oaep_md(MessageDigest::sha256())显式设置内容摘要。MGF 1摘要使用内容摘要隐式设置(因为在发布的示例中内容和MGF 1摘要是相同的,所以不需要在这里显式设置MGF 1摘要)。
如果要使用不同的MGF 1摘要,则必须使用set_rsa_mgf1_md()。如果要设置标签,则必须使用set_rsa_oaep_label()。但是,请注意,标签实际上始终为空(出于兼容性原因,也不应更改)。
测试:使用发布的Python代码,base64编码的32字节密钥

AAECAwQFBgcICQoLDA0OD/Dx8vP09fb3+Pn6+/z9/v8=

加密方式如下(Base64编码):

oU1PwQRE0ZEr71OOfoNHLpmjXyTAfdZroeQhX4WLAhXpfTMkEMJ0YptHgFDirJ5fdZ9yRl+y1y6jZSpG7oj5wtJkDa4BeLba++Q1UZcKlne4rfYMEPDrkTCjyHyNskuJuLh3FW+HCp70tRzvgSoBpoIwyxWl3VREYRcJEAdzGwRj0d6JNCO4M3BHX7g59to5urOkTXB7MfcAEz1Ba4AdeNYrZK4XD8GjAqnI95X3Z4F8PoLGMP1eMif0fpNizxZo7hzTfEsfjdlkyfTWLZfxuZ9qZMIpkiQNNEWWMt66FmVgFyi8zngz/Tj5Tk7cNzrWOT5BDaFCxrJF1kHoHobojA==

注意,OAEP是不确定的,即用相同的密钥和明文重复加密产生不同的密文。
此密文可以用以下Rust代码解密:

use openssl::encrypt::{Decrypter};
use openssl::rsa::{Rsa, Padding};
use openssl::pkey::PKey;
use openssl::hash::MessageDigest;
use base64::{engine::general_purpose, Engine as _};

fn main() {

    // Import private key
    let pem_private = "-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAunF5aDa6HCfLMMI/MZLT5hDk304CU+ypFMFiBjowQdUMQKYH
Z+fklB7GpLxCatxYJ/hZ7rjfHH3Klq20/Y1EbYDRopyTSfkrTzPzwsX4Ur/l25Ct
dQldhHCTMgwf/Ev/buBNobfzdZE+Dhdv5lQwKtjI43lDKvAi5kEet2TFwfJcJrBi
RJeEcLfVgWTXGRQn7gngWKykUu5rS83eAU1xH9FLojQfyia89/EykiOO7/3UWwd+
MATZ9HLjSx2/Lf3g2jr81eifEmYDlri/OZp4OhZu+0Bo1LXloCTe+vmIQ2YCX7Ea
tUOuyQMt2Vwx4uV+d/A3DP6PtMGBKpF8St4iGwIDAQABAoIBAEpSY9BMSKJippgY
RvKvEjNbNrFhuoHUDI7OjBHpbkU/9XNr+/XKtg7pucv/lAZfMfE1Cjyki6Qi7Phl
5IlSoB16xZaqDfjmEAKxthFFs7jg8HM3WD4YbqQV8Ed6F+IONZPwbGH0H2QVcwRR
CXVqyAy8gFBVjZX3RiI9gU4gKMkn8qpmpr5lvG7L3PHKIhpWdvFAvOf16sfcDs43
hqEZAh+z3EzJXPRe0sUrYcF/5NVQV5jTh2vh8xjoDv1t5NSw6iW6tsCo2U1t4lRI
NlaHY8YASzJtDLnkhqCOiLmmUjzMhRDN4BrwtvnAwSNki/2poYk1Gv1Q5U1cPyCm
0rmq/bkCgYEA3e+jND6OS6ofGYUN6G4RapHzuRAV8ux1C9eXMOdZFbcBehn/ydhz
R48LIPTW9HiRE00um27lXfW5/POCaEUvfOp1UxTWeHZ4xICo40PBo383ZKW1MbES
1oiMbjkEqSFGRnTItnLU07bKbzLA7I0UWHWCEAnv0g7HRxk973FAsm8CgYEA1w8+
olZ2POBYeYgw1a0DkeJWKMQi/4pAgyYwustZo0dHlRXQT0OI9XQ0j1PZWoQS28tF
cmoEAg6f5MUDpdM9swS0SOCPI1Lc/f/Slus3u1O3UCezk37pneSPezskDhvV2cCl
JEYH8m/zwDAUlEi4KLIt/H/jgtyDd6pbxxc78RUCgYEAiE6VAxJknM4oeakBiL6J
TdXEReY+RMu7e4F2518/lJmoe5CaTCL3cnzFTgFyQAYIvD0MIgSzNMkl6Ni6QEY1
y1fIpTVIIAZLWAzZLXPA6yTIJbWsmo9xzXdiIJQ+a433NnClkYDne/xpSnB2kxJ2
63mIX0drFq1i8STsqDH7lVsCgYBWpQmzFeqlNC3xKPGj5QTfLbVQz1TaZ7T+IdDY
MT14DyvD4PoANVFksuDKLhoP4c5HR2o/Yn8i5Ql+ffGuSaE+EtMf2XlR3fyzSPJr
Y3Ecw+nDHXu4HRW6S2+TUoyAMq7CAF+Icb6Z6ojmEXj5FSM9Iixs4omjG3zMJZK8
b5vy0QKBgQCz0W7UmxNqT4Lzhyh0xj6+4Cm5rFlWznEAPKxvNNU9/Fv1D3tV7cpz
BI880NvTmlXkML1Dffg8RVyemL8I+ooeFnatdPYuzqNXw5zHMzkDfQynIdnjQB6z
UjjMiwwgZvvsG8hwLEtk9FTvPoMywAb4mZuQBQkFn5HuC2aOZjktdA==
-----END RSA PRIVATE KEY-----"; 
    let private_key = Rsa::private_key_from_pem(pem_private.as_bytes()).unwrap();
    let private_key = PKey::from_rsa(private_key).unwrap();
    
    // Import Base64 encoded ciphertext
    let data = "oU1PwQRE0ZEr71OOfoNHLpmjXyTAfdZroeQhX4WLAhXpfTMkEMJ0YptHgFDirJ5fdZ9yRl+y1y6jZSpG7oj5wtJkDa4BeLba++Q1UZcKlne4rfYMEPDrkTCjyHyNskuJuLh3FW+HCp70tRzvgSoBpoIwyxWl3VREYRcJEAdzGwRj0d6JNCO4M3BHX7g59to5urOkTXB7MfcAEz1Ba4AdeNYrZK4XD8GjAqnI95X3Z4F8PoLGMP1eMif0fpNizxZo7hzTfEsfjdlkyfTWLZfxuZ9qZMIpkiQNNEWWMt66FmVgFyi8zngz/Tj5Tk7cNzrWOT5BDaFCxrJF1kHoHobojA==";
    let encrypted = general_purpose::STANDARD.decode(&data).unwrap();

    // Decrypt ciphertext
    let mut decrypter = Decrypter::new(&private_key).unwrap();
    decrypter.set_rsa_padding(Padding::PKCS1_OAEP).unwrap();
    decrypter.set_rsa_oaep_md(MessageDigest::sha256()).unwrap();
    //decrypter.set_rsa_mgf1_md(MessageDigest::sha256()).unwrap(); // implicitly set
    
    // Create an output buffer
    let buffer_len = decrypter.decrypt_len(&encrypted).unwrap();
    let mut decrypted = vec![0; buffer_len];
    
    // Encrypt and truncate buffer
    let decrypted_len = decrypter.decrypt(&encrypted, &mut decrypted).unwrap();
    decrypted.truncate(decrypted_len);
    
    println!("Decrypted: {}", general_purpose::STANDARD.encode(&decrypted)); // Decrypted: AAECAwQFBgcICQoLDA0OD/Dx8vP09fb3+Pn6+/z9/v8=
}

相关问题