crypto.rs (10027B)
1 /* 2 * This file is part of LibEuFin. 3 * Copyright (C) 2026 Taler Systems S.A. 4 5 * LibEuFin is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU Affero General Public License as 7 * published by the Free Software Foundation; either version 3, or 8 * (at your option) any later version. 9 10 * LibEuFin is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General 13 * Public License for more details. 14 15 * You should have received a copy of the GNU Affero General Public 16 * License along with LibEuFin; see the file COPYING. If not, see 17 * <http://www.gnu.org/licenses/> 18 */ 19 20 use aws_lc_rs::{ 21 cipher::{ 22 AES_128, DecryptingKey, DecryptionContext, EncryptingKey, EncryptionContext, 23 UnboundCipherKey, 24 }, 25 digest::{Context, Digest, SHA256}, 26 encoding::AsDer, 27 iv::FixedLength, 28 rand::SystemRandom, 29 rsa::{ 30 KeyPair, Pkcs1PrivateDecryptingKey, Pkcs1PublicEncryptingKey, PrivateDecryptingKey, 31 PublicEncryptingKey, PublicKey, 32 }, 33 signature::{RSA_PSS_2048_8192_SHA256, RSA_PSS_SHA256, UnparsedPublicKey}, 34 }; 35 use jiff::{Timestamp, Zoned, tz::TimeZone}; 36 use rand::{TryRng, rngs::SysRng}; 37 use rcgen::{BasicConstraints, CertificateParams, DnType, IsCa, KeyUsagePurpose}; 38 use taler_common::encoding::{base64, hex}; 39 use x509_parser::prelude::{FromDer as _, X509Certificate}; 40 41 /// Generate a self-signed X.509 certificate from an RSA private key (PEM or DER) 42 pub fn x509_certificate_from_rsa_private( 43 pem: &str, 44 name: &str, 45 ) -> Result<rcgen::Certificate, rcgen::Error> { 46 let keys = rcgen::KeyPair::from_pem(pem).unwrap(); 47 let mut params = CertificateParams::new(vec![])?; 48 49 // Set subject/issuer CN 50 params.distinguished_name.push(DnType::CommonName, name); 51 52 let now = Zoned::new(Timestamp::now(), TimeZone::UTC).date(); 53 54 // 1000-year validity 55 params.not_before = rcgen::date_time_ymd(now.year() as i32, now.month() as u8, now.day() as u8); 56 params.not_after = 57 rcgen::date_time_ymd(now.year() as i32 + 1000, now.month() as u8, now.day() as u8); 58 59 // CA: true (basicConstraints) 60 params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); 61 62 // Key usage flags 63 params.key_usages = vec![ 64 KeyUsagePurpose::DigitalSignature, 65 KeyUsagePurpose::ContentCommitment, // NonRepudiation 66 KeyUsagePurpose::KeyEncipherment, 67 KeyUsagePurpose::DataEncipherment, 68 KeyUsagePurpose::KeyAgreement, 69 KeyUsagePurpose::KeyCertSign, 70 KeyUsagePurpose::CrlSign, 71 KeyUsagePurpose::EncipherOnly, 72 KeyUsagePurpose::DecipherOnly, 73 ]; 74 75 let cert = params.self_signed(&keys)?; 76 Ok(cert) 77 } 78 79 /** Create an RSA public key from its components: [modulus] and [exponent] */ 80 pub fn rsa_pub_from_component(modulus: &[u8], exponent: &[u8]) -> anyhow::Result<PublicKey> { 81 let key: PublicEncryptingKey = aws_lc_rs::rsa::PublicKeyComponents { 82 n: modulus, 83 e: exponent, 84 } 85 .try_into()?; 86 Ok(PublicKey::from_der(key.as_der()?.as_ref())?) 87 } 88 89 /// Extract an RSA public key from a X.509 certificate 90 pub fn rsa_private_from_b64_x509_certificate(encoded: &str) -> anyhow::Result<PublicKey> { 91 let der = base64::decode(encoded)?; 92 let (_, cert) = X509Certificate::from_der(&der)?; 93 let issuer_public_key = cert.public_key(); 94 Ok(PublicKey::from_der(issuer_public_key.raw)?) 95 } 96 97 /// Hash an RSA public key according to the EBICS standard (EBICS 2.5: 4.4.1.2.3). 98 pub fn ebics_pub_key_hash(public_key: &PublicKey) -> Digest { 99 let mut ctx = Context::new(&SHA256); 100 let hex_encoded = |input: &[u8], ctx: &mut Context| { 101 let encoded = hex::encode(input); 102 if encoded.starts_with('0') { 103 ctx.update(&encoded.as_bytes()[1..]); 104 } else { 105 ctx.update(encoded.as_bytes()); 106 } 107 }; 108 109 hex_encoded( 110 public_key.exponent().big_endian_without_leading_zero(), 111 &mut ctx, 112 ); 113 ctx.update(b" "); 114 hex_encoded( 115 public_key.modulus().big_endian_without_leading_zero(), 116 &mut ctx, 117 ); 118 ctx.finish() 119 } 120 121 pub fn gen_ebics_e002_key(pub_key: &PublicKey) -> ([u8; 16], Vec<u8>) { 122 let mut transaction_key = [0u8; 16]; 123 SysRng.try_fill_bytes(&mut transaction_key).unwrap(); 124 125 let key = Pkcs1PublicEncryptingKey::new( 126 PublicEncryptingKey::from_der(pub_key.as_der().unwrap().as_ref()).unwrap(), 127 ) 128 .unwrap(); 129 let mut encrypted_key = vec![0; key.ciphertext_size()]; 130 key.encrypt(&transaction_key, &mut encrypted_key).unwrap(); 131 132 (transaction_key, encrypted_key) 133 } 134 135 pub fn encrypt_ebics_e002(transaction_key: &[u8; 16], mut data: Vec<u8>) -> Vec<u8> { 136 let block_size = 16; 137 let padding_len = block_size - (data.len() % block_size); 138 139 // Add padding 140 for i in 0..padding_len { 141 if i == padding_len - 1 { 142 data.push(padding_len as u8); 143 } else { 144 data.push(0); 145 } 146 } 147 148 let iv = FixedLength::from([0u8; 16]); 149 let enc_key = 150 EncryptingKey::cbc(UnboundCipherKey::new(&AES_128, transaction_key).unwrap()).unwrap(); 151 enc_key 152 .less_safe_encrypt(&mut data, EncryptionContext::Iv128(iv)) 153 .unwrap(); 154 155 data 156 } 157 158 pub fn decrypt_ebics_e002( 159 transaction_key: &DecryptingKey, 160 mut encrypted_data: Vec<u8>, 161 ) -> Result<Vec<u8>, ()> { 162 let iv = FixedLength::from([0u8; 16]); 163 164 let plaintext = transaction_key.decrypt(&mut encrypted_data, DecryptionContext::Iv128(iv))?; 165 166 // Strip X9.23 / ANSI X9.23 padding: 167 // The last byte holds the number of padding bytes to remove. 168 let pad_len = *plaintext.last().ok_or(())? as usize; 169 if pad_len == 0 || pad_len > 16 || pad_len > plaintext.len() { 170 return Err(()); 171 } 172 let decoded = plaintext.len() - pad_len; 173 encrypted_data.truncate(decoded); 174 Ok(encrypted_data) 175 } 176 177 pub fn decrypt_ebics_e002_key( 178 private_key: PrivateDecryptingKey, 179 encrypted_transaction_key: &[u8], 180 ) -> DecryptingKey { 181 let private_key = Pkcs1PrivateDecryptingKey::new(private_key).unwrap(); 182 let mut plaintext = vec![0u8; private_key.min_output_size()]; 183 let cipher = private_key 184 .decrypt(encrypted_transaction_key, &mut plaintext) 185 .unwrap(); 186 let cipher_key = UnboundCipherKey::new(&AES_128, cipher).unwrap(); 187 DecryptingKey::cbc(cipher_key).unwrap() 188 } 189 190 pub fn digest_ebics_order_a006(order_data: &[u8]) -> Digest { 191 let mut digest = Context::new(&SHA256); 192 for chunk in order_data.split(|b| matches!(b, b'\r' | b'\n' | b'\x1a')) { 193 digest.update(chunk); 194 } 195 digest.finish() 196 } 197 198 pub fn sign_ebics_a006(data: &[u8], key_pair: &KeyPair) -> Vec<u8> { 199 let mut sig = vec![0; key_pair.public_modulus_len()]; 200 key_pair 201 .sign(&RSA_PSS_SHA256, &SystemRandom::new(), data, &mut sig) 202 .unwrap(); 203 sig 204 } 205 206 pub fn verify_ebics_a006(sig: &[u8], data: &[u8], public_key_der: &PublicKey) -> bool { 207 UnparsedPublicKey::new(&RSA_PSS_2048_8192_SHA256, public_key_der.as_ref()) 208 .verify(data, sig) 209 .is_ok() 210 } 211 212 #[cfg(test)] 213 mod test { 214 use aws_lc_rs::{ 215 encoding::AsDer, 216 rsa::{KeyPair, KeySize, PrivateDecryptingKey, PublicKey}, 217 signature::KeyPair as _, 218 }; 219 use taler_common::encoding::hex; 220 221 use crate::crypto::{ 222 decrypt_ebics_e002, decrypt_ebics_e002_key, ebics_pub_key_hash, encrypt_ebics_e002, 223 gen_ebics_e002_key, rsa_pub_from_component, sign_ebics_a006, verify_ebics_a006, 224 }; 225 226 #[test] 227 fn e002() { 228 let data = b"Hello, World!"; 229 let key = PrivateDecryptingKey::generate(KeySize::Rsa2048).unwrap(); 230 231 let (tx_key, encrypted_key) = gen_ebics_e002_key( 232 &PublicKey::from_der(key.public_key().as_der().unwrap().as_ref()).unwrap(), 233 ); 234 let enc = encrypt_ebics_e002(&tx_key, data.to_vec()); 235 let key = decrypt_ebics_e002_key(key, &encrypted_key); 236 let dec = decrypt_ebics_e002(&key, enc).unwrap(); 237 assert_eq!(&data, &dec.as_slice()); 238 } 239 240 #[test] 241 fn a006() { 242 let data = b"Hello, World!"; 243 let key_pair = KeyPair::generate(KeySize::Rsa2048).unwrap(); 244 let sig = sign_ebics_a006(data, &key_pair); 245 assert!(verify_ebics_a006(&sig, data, key_pair.public_key())); 246 } 247 248 #[test] 249 fn public_key_hash() { 250 let exponent = "01 00 01".replace(|it: char| it.is_whitespace(), ""); 251 let modulus = " 252 EB BD B8 E3 73 45 60 06 44 A1 AD 6A 25 33 65 F5 253 9C EB E5 93 E0 51 72 77 90 6B F0 58 A8 89 EB 00 254 C6 0B 37 38 F3 3C 55 F2 4D 83 D0 33 C3 A8 F0 3C 255 82 4E AF 78 51 D6 F4 71 6A CC 9C 10 2A 58 C9 5F 256 3D 30 B4 31 D7 1B 79 6D 43 AA F9 75 B5 7E 0B 4A 257 55 52 1D 7C AC 8F 92 B0 AE 9F CF 5F 16 5C 6A D1 258 88 DB E2 48 E7 78 43 F9 18 63 29 45 ED 6C 08 6C 259 16 1C DE F3 02 01 23 8A 58 35 43 2B 2E C5 3F 6F 260 33 B7 A3 46 E1 75 BD 98 7C 6D 55 DE 71 11 56 3D 261 7A 2C 85 42 98 42 DF 94 BF E8 8B 76 84 13 3E CA 262 0E 8D 12 57 D6 8A CF 82 DE B7 D7 BB BC 45 AE 25 263 95 76 00 19 08 AA D2 C8 A7 D8 10 37 88 96 B9 98 264 14 B4 B0 65 F3 36 CE 93 F7 46 12 58 9F E7 79 33 265 D5 BE 0D 0E F8 E7 E0 A9 C3 10 51 A1 3E A4 4F 67 266 5E 75 8C 9D E6 FE 27 B6 3C CF 61 9B 31 D4 D0 22 267 B9 2E 4C AF 5F D6 4B 1F F0 4D 06 5F 68 EB 0B 71 268 " 269 .replace(|it: char| it.is_whitespace(), ""); 270 let expected = " 271 72 71 D5 83 B4 24 A6 DA 0B 7B 22 24 3B E2 B8 8C 272 6E A6 0F 9F 76 11 FD 18 BE 2C E8 8B 21 03 A9 41 273 " 274 .replace(|it: char| it.is_whitespace(), ""); 275 let key = rsa_pub_from_component( 276 &hex::decode(modulus).unwrap(), 277 &hex::decode(exponent).unwrap(), 278 ) 279 .unwrap(); 280 let hash = ebics_pub_key_hash(&key); 281 assert_eq!(&hex::decode(expected).unwrap(), hash.as_ref()); 282 } 283 }