1use super::{
10 Algorithm, CryptoError, ED25519_PUBLIC_KEY_LEN, HashContext, HashImpl, HashOutput,
11 MLDSA44_MESSAGE_CAPACITY, Sha1, Sha256, Sha512, SigningKey, VerifyingKey,
12 aws_lc_mldsa::MlDsa44,
13 mldsa::{self, CONTEXT, SIGNATURE_LEN, Seed, library_error},
14 rsa_private_key_heap_size,
15};
16use crate::{
17 Error, Result,
18 dkim::Canonicalization,
19 headers::{Writable, Writer},
20};
21use aws_lc_rs::digest::{Context, SHA1_FOR_LEGACY_USE_ONLY, SHA256, SHA512};
22use aws_lc_rs::rand::SystemRandom;
23use aws_lc_rs::signature::{
24 ED25519, Ed25519KeyPair, KeyPair, RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
25 RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY, RSA_PKCS1_SHA256, RsaKeyPair,
26 UnparsedPublicKey,
27};
28use rustls_pki_types::{PrivateKeyDer, PrivatePkcs1KeyDer, PrivatePkcs8KeyDer, pem::PemObject};
29use std::marker::PhantomData;
30
31const ED25519_PRIVATE_KEY_HEAP_SIZE: usize = 112;
32const MLDSA44_PRIVATE_KEY_HEAP_SIZE: usize = 4096;
33const MLDSA44_PUBLIC_KEY_HEAP_SIZE: usize = 1600;
34
35#[derive(Debug)]
40pub struct RsaKey<T> {
41 inner: RsaKeyPair,
42 rng: SystemRandom,
43 padding: PhantomData<T>,
44}
45
46impl<T: HashImpl> RsaKey<T> {
47 #[deprecated(since = "0.7.4", note = "use `from_key_der()` instead")]
54 pub fn from_pkcs8_pem(pkcs8_pem: &str) -> Result<Self> {
55 Self::from_key_der(PrivateKeyDer::Pkcs8(
56 PrivatePkcs8KeyDer::from_pem_slice(pkcs8_pem.as_bytes())
57 .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
58 ))
59 }
60
61 #[deprecated(since = "0.7.4", note = "use `from_key_der()` instead")]
68 pub fn from_pkcs8_der(pkcs8_der: &[u8]) -> Result<Self> {
69 Self::from_key_der(PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(pkcs8_der)))
70 }
71
72 #[deprecated(since = "0.7.4", note = "use `from_key_der()` instead")]
80 pub fn from_rsa_pem(rsa_pem: &str) -> Result<Self> {
81 Self::from_key_der(PrivateKeyDer::Pkcs1(
82 PrivatePkcs1KeyDer::from_pem_slice(rsa_pem.as_bytes())
83 .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
84 ))
85 }
86
87 #[deprecated(since = "0.7.4", note = "use `from_key_der()` instead")]
94 pub fn from_der(der: &[u8]) -> Result<Self> {
95 Self::from_key_der(PrivateKeyDer::Pkcs1(PrivatePkcs1KeyDer::from(der)))
96 }
97
98 pub fn from_key_der(key_der: PrivateKeyDer<'_>) -> Result<Self> {
107 let inner = match key_der {
108 PrivateKeyDer::Pkcs1(der) => RsaKeyPair::from_der(der.secret_pkcs1_der())
109 .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
110 PrivateKeyDer::Pkcs8(der) => RsaKeyPair::from_pkcs8(der.secret_pkcs8_der())
111 .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
112 _ => {
113 return Err(Error::Crypto(CryptoError::Library(
114 "Unsupported RSA key format".to_string(),
115 )));
116 }
117 };
118
119 Ok(Self {
120 inner,
121 rng: SystemRandom::new(),
122 padding: PhantomData,
123 })
124 }
125
126 pub fn public_key(&self) -> Vec<u8> {
129 self.inner.public_key().as_ref().to_vec()
130 }
131}
132
133impl SigningKey for RsaKey<Sha256> {
134 type Hasher = Sha256;
135
136 fn sign(&self, input: impl Writable) -> Result<Vec<u8>> {
137 let mut data = Vec::with_capacity(256);
138 input.write(&mut data);
139
140 let mut signature = vec![0; self.inner.public_key().modulus_len()];
141 self.inner
142 .sign(&RSA_PKCS1_SHA256, &self.rng, &data, &mut signature)
143 .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?;
144 Ok(signature)
145 }
146
147 fn algorithm(&self) -> Algorithm {
148 Algorithm::RsaSha256
149 }
150
151 fn heap_size(&self) -> usize {
152 rsa_private_key_heap_size(self.inner.public_key().modulus_len())
153 }
154}
155
156pub struct Ed25519Key {
161 inner: Ed25519KeyPair,
162}
163
164impl Ed25519Key {
165 pub fn generate_pkcs8() -> Result<Vec<u8>> {
173 Ok(Ed25519KeyPair::generate_pkcs8(&SystemRandom::new())
174 .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?
175 .as_ref()
176 .to_vec())
177 }
178
179 pub fn from_pkcs8_der(pkcs8_der: &[u8]) -> Result<Self> {
189 Ok(Self {
190 inner: Ed25519KeyPair::from_pkcs8(pkcs8_der)
191 .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
192 })
193 }
194
195 pub fn from_pkcs8_maybe_unchecked_der(pkcs8_der: &[u8]) -> Result<Self> {
205 Ok(Self {
206 inner: Ed25519KeyPair::from_pkcs8_maybe_unchecked(pkcs8_der)
207 .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
208 })
209 }
210
211 pub fn from_seed_and_public_key(seed: &[u8], public_key: &[u8]) -> Result<Self> {
219 Ok(Self {
220 inner: Ed25519KeyPair::from_seed_and_public_key(seed, public_key)
221 .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?,
222 })
223 }
224
225 pub fn public_key(&self) -> Vec<u8> {
228 self.inner.public_key().as_ref().to_vec()
229 }
230}
231
232impl SigningKey for Ed25519Key {
233 type Hasher = Sha256;
234
235 fn sign(&self, input: impl Writable) -> Result<Vec<u8>> {
236 let mut data = Sha256::hasher();
237 input.write(&mut data);
238 Ok(self.inner.sign(data.complete().as_ref()).as_ref().to_vec())
239 }
240
241 fn algorithm(&self) -> Algorithm {
242 Algorithm::Ed25519Sha256
243 }
244
245 fn heap_size(&self) -> usize {
246 ED25519_PRIVATE_KEY_HEAP_SIZE
247 }
248}
249
250pub(crate) struct RsaPublicKey {
251 key: Vec<u8>,
252}
253
254impl RsaPublicKey {
255 pub(crate) fn verifying_key_from_bytes(
256 bytes: &[u8],
257 ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
258 Ok(Box::new(Self {
259 key: try_strip_rsa_prefix(bytes).unwrap_or(bytes).to_vec(),
260 }))
261 }
262}
263
264fn rsa_modulus_bits(key: &[u8]) -> Option<usize> {
266 if *key.first()? != DER_SEQUENCE_TAG {
267 return None;
268 }
269 let (_, rest) = decode_multi_byte_len(&key[1..])?;
270 if *rest.first()? != DER_INTEGER_TAG {
271 return None;
272 }
273 let (len, after_len) = decode_multi_byte_len(&rest[1..])?;
274 after_len
275 .get(..len)?
276 .iter()
277 .position(|&b| b != 0)
278 .map(|leading_zeros| (len - leading_zeros) * 8)
279}
280
281fn try_strip_rsa_prefix(bytes: &[u8]) -> Option<&[u8]> {
285 if *bytes.first()? != DER_SEQUENCE_TAG {
286 return None;
287 }
288
289 let (_, bytes) = decode_multi_byte_len(&bytes[1..])?;
290 if *bytes.first()? != DER_SEQUENCE_TAG {
291 return None;
292 }
293
294 let (byte_len, bytes) = decode_multi_byte_len(&bytes[1..])?;
295 if *bytes.first()? != DER_OBJECT_ID_TAG || byte_len != 13 {
296 return None;
297 }
298
299 let bytes = bytes.get(13..)?;
300 if *bytes.first()? != DER_BIT_STRING_TAG {
301 return None;
302 }
303
304 decode_multi_byte_len(&bytes[1..]).and_then(|(_, bytes)| bytes.get(1..))
305}
306
307fn decode_multi_byte_len(bytes: &[u8]) -> Option<(usize, &[u8])> {
308 if bytes.first()? & 0x80 == 0 {
309 return Some((bytes[0] as usize, &bytes[1..]));
310 }
311
312 let len_len = (bytes[0] & 0x7f) as usize;
313 if bytes.len() < len_len + 1 {
314 return None;
315 }
316
317 let mut len = 0;
318 for i in 0..len_len {
319 len = (len << 8) | bytes[1 + i] as usize;
320 }
321
322 Some((len, &bytes[len_len + 1..]))
323}
324
325const DER_OBJECT_ID_TAG: u8 = 0x06;
326const DER_BIT_STRING_TAG: u8 = 0x03;
327const DER_SEQUENCE_TAG: u8 = 0x30;
328const DER_INTEGER_TAG: u8 = 0x02;
329
330impl VerifyingKey for RsaPublicKey {
331 fn verify<'a>(
332 &self,
333 headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
334 signature: &[u8],
335 canonicalization: Canonicalization,
336 algorithm: Algorithm,
337 ) -> Result<()> {
338 let mut data = Vec::with_capacity(256);
339 canonicalization.canonicalize_headers(headers, &mut data);
340
341 match algorithm {
342 Algorithm::RsaSha256 => UnparsedPublicKey::new(
343 &RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
344 self.key.as_slice(),
345 )
346 .verify(&data, signature)
347 .map_err(|_| Error::Crypto(CryptoError::FailedVerification)),
348 Algorithm::RsaSha1 => UnparsedPublicKey::new(
349 &RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
350 self.key.as_slice(),
351 )
352 .verify(&data, signature)
353 .map_err(|_| Error::Crypto(CryptoError::FailedVerification)),
354 Algorithm::Ed25519Sha256 | Algorithm::MlDsa44 => {
355 Err(Error::Crypto(CryptoError::IncompatibleAlgorithms))
356 }
357 }
358 }
359
360 fn verify_bytes(&self, input: &[u8], signature: &[u8], algorithm: Algorithm) -> Result<()> {
361 match algorithm {
362 Algorithm::RsaSha256 => UnparsedPublicKey::new(
363 &RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY,
364 self.key.as_slice(),
365 )
366 .verify(input, signature)
367 .map_err(|_| Error::Crypto(CryptoError::FailedVerification)),
368 Algorithm::RsaSha1 => UnparsedPublicKey::new(
369 &RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY,
370 self.key.as_slice(),
371 )
372 .verify(input, signature)
373 .map_err(|_| Error::Crypto(CryptoError::FailedVerification)),
374 Algorithm::Ed25519Sha256 | Algorithm::MlDsa44 => {
375 Err(Error::Crypto(CryptoError::IncompatibleAlgorithms))
376 }
377 }
378 }
379
380 fn public_key_bits(&self) -> usize {
381 rsa_modulus_bits(&self.key).unwrap_or_default()
382 }
383
384 fn heap_size(&self) -> usize {
385 self.key.capacity()
386 }
387}
388
389pub(crate) struct Ed25519PublicKey {
390 inner: UnparsedPublicKey<[u8; ED25519_PUBLIC_KEY_LEN]>,
391}
392
393impl Ed25519PublicKey {
394 pub(crate) fn verifying_key_from_bytes(
395 bytes: &[u8],
396 ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
397 let key: [u8; ED25519_PUBLIC_KEY_LEN] = bytes
398 .try_into()
399 .map_err(|_| Error::Crypto(CryptoError::MalformedPublicKey))?;
400 Ok(Box::new(Self {
401 inner: UnparsedPublicKey::new(&ED25519, key),
402 }))
403 }
404}
405
406impl VerifyingKey for Ed25519PublicKey {
407 fn verify<'a>(
408 &self,
409 headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
410 signature: &[u8],
411 canonicalization: Canonicalization,
412 algorithm: Algorithm,
413 ) -> Result<()> {
414 if !matches!(algorithm, Algorithm::Ed25519Sha256) {
415 return Err(Error::Crypto(CryptoError::IncompatibleAlgorithms));
416 }
417
418 let mut hasher = Sha256::hasher();
419 canonicalization.canonicalize_headers(headers, &mut hasher);
420 self.inner
421 .verify(hasher.complete().as_ref(), signature)
422 .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))
423 }
424
425 fn verify_bytes(&self, input: &[u8], signature: &[u8], algorithm: Algorithm) -> Result<()> {
426 if !matches!(algorithm, Algorithm::Ed25519Sha256) {
427 return Err(Error::Crypto(CryptoError::IncompatibleAlgorithms));
428 }
429
430 let mut hasher = Sha256::hasher();
431 hasher.write(input);
432 self.inner
433 .verify(hasher.complete().as_ref(), signature)
434 .map_err(|_| Error::Crypto(CryptoError::FailedVerification))
435 }
436}
437
438pub struct MlDsa44Key {
445 inner: MlDsa44,
446}
447
448impl MlDsa44Key {
449 pub fn generate_pkcs8() -> Result<Vec<u8>> {
458 let mut seed = Seed::default();
459 aws_lc_rs::rand::fill(&mut seed)
460 .map_err(|err| Error::Crypto(CryptoError::Library(err.to_string())))?;
461 Ok(mldsa::pkcs8_der(&seed))
462 }
463
464 pub fn from_pkcs8_der(pkcs8_der: &[u8]) -> Result<Self> {
473 Self::from_seed(mldsa::seed_from_pkcs8_der(pkcs8_der)?)
474 }
475
476 pub fn from_raw_private_key(raw: &[u8]) -> Result<Self> {
483 Self::from_seed(mldsa::seed_from_raw(raw)?)
484 }
485
486 fn from_seed(seed: &Seed) -> Result<Self> {
487 MlDsa44::from_seed(seed)
488 .map(|inner| Self { inner })
489 .ok_or_else(|| library_error("Invalid ML-DSA-44 seed"))
490 }
491
492 pub fn public_key(&self) -> Result<Vec<u8>> {
500 self.inner
501 .public_key()
502 .map(Vec::from)
503 .ok_or_else(|| library_error("Cannot export the ML-DSA-44 public key"))
504 }
505}
506
507impl SigningKey for MlDsa44Key {
508 type Hasher = Sha256;
509
510 fn sign(&self, input: impl Writable) -> Result<Vec<u8>> {
511 let mut message = Vec::with_capacity(MLDSA44_MESSAGE_CAPACITY);
512 input.write(&mut message);
513 self.inner
514 .sign(&message, CONTEXT)
515 .map(Vec::from)
516 .ok_or_else(|| library_error("ML-DSA-44 signing failed"))
517 }
518
519 fn algorithm(&self) -> Algorithm {
520 Algorithm::MlDsa44
521 }
522
523 fn heap_size(&self) -> usize {
524 MLDSA44_PRIVATE_KEY_HEAP_SIZE
525 }
526}
527
528pub(crate) struct MlDsa44PublicKey {
529 inner: MlDsa44,
530}
531
532impl MlDsa44PublicKey {
533 pub(crate) fn verifying_key_from_bytes(
534 bytes: &[u8],
535 ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
536 let key = mldsa::public_key_from_bytes(bytes)?;
537 Ok(Box::new(Self {
538 inner: MlDsa44::from_public_key(key)
539 .ok_or(Error::Crypto(CryptoError::MalformedPublicKey))?,
540 }))
541 }
542}
543
544impl VerifyingKey for MlDsa44PublicKey {
545 fn verify<'a>(
546 &self,
547 _: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
548 _: &[u8],
549 _: Canonicalization,
550 _: Algorithm,
551 ) -> Result<()> {
552 Err(Error::Crypto(CryptoError::IncompatibleAlgorithms))
553 }
554
555 fn verify_bytes(&self, input: &[u8], signature: &[u8], algorithm: Algorithm) -> Result<()> {
556 if !matches!(algorithm, Algorithm::MlDsa44) {
557 return Err(Error::Crypto(CryptoError::IncompatibleAlgorithms));
558 }
559 let signature: &[u8; SIGNATURE_LEN] = signature
560 .try_into()
561 .map_err(|_| Error::Crypto(CryptoError::FailedVerification))?;
562 if self.inner.verify(input, CONTEXT, signature) {
563 Ok(())
564 } else {
565 Err(Error::Crypto(CryptoError::FailedVerification))
566 }
567 }
568
569 fn heap_size(&self) -> usize {
570 MLDSA44_PUBLIC_KEY_HEAP_SIZE
571 }
572}
573
574impl HashImpl for Sha1 {
575 type Context = Context;
576
577 fn hasher() -> Self::Context {
578 Context::new(&SHA1_FOR_LEGACY_USE_ONLY)
579 }
580}
581
582impl HashImpl for Sha256 {
583 type Context = Context;
584
585 fn hasher() -> Self::Context {
586 Context::new(&SHA256)
587 }
588}
589
590impl HashImpl for Sha512 {
591 type Context = Context;
592
593 fn hasher() -> Self::Context {
594 Context::new(&SHA512)
595 }
596}
597
598impl HashContext for Context {
599 fn complete(self) -> HashOutput {
600 HashOutput::Digest(self.finish())
601 }
602}
603
604impl Writer for Context {
605 fn write(&mut self, data: &[u8]) {
606 self.update(data);
607 }
608}
609
610#[cfg(test)]
611mod tests {
612 use super::*;
613
614 #[test]
615 fn from_key_der_pkcs1() {
616 let key_der = PrivateKeyDer::from_pem_slice(PKCS1_PEM.as_bytes()).unwrap();
617 assert!(matches!(key_der, PrivateKeyDer::Pkcs1(_)));
618 RsaKey::<Sha256>::from_key_der(key_der).unwrap();
619 }
620
621 #[test]
622 fn from_key_der_pkcs8() {
623 let key_der = PrivateKeyDer::from_pem_slice(PKCS8_PEM.as_bytes()).unwrap();
624 assert!(matches!(key_der, PrivateKeyDer::Pkcs8(_)));
625 RsaKey::<Sha256>::from_key_der(key_der).unwrap();
626 }
627
628 const PKCS1_PEM: &str = r#"-----BEGIN RSA PRIVATE KEY-----
629MIIEoAIBAAKCAQEAplSshLNG7gYj7LckWBQ5Gg1mrFGj2soo3VuMKSbvfR6tMrnj
630khKUSl3TWQyKdkuOOf4EzAyxhJdq/hWGvMdwfwH2q4UzjjcaRHDP54oBH6WHxyAn
631UUkJTFfJo2i8jFE/um09igLr5sEaKMiHgjQIdUScuQRGqKhqS9e4tPpTnfP4ayvM
632zVvD1ptUnaV4O9+GkpEwx/vLVXItMO2KNXXKADYBuWcY9g+Dlpp637radmLJjnvj
633bCJipWjuVzUEQvIvf3x1dZ4b899Bycp4uScmdz5brfxkhLaA9vchnmr+F7aAuwwK
634N5X2Ep6n5d1M0XjA02Z9Zi2W4NkZiNBBmb/f6QIDAQABAoIBAAPzPANNGv4L98jx
635+C3o/F/YbyE1sXmV9lP8I1nr1+FbETvEleQSHGL1aPpIVbZ6/gugXdP3E4qFqmUS
636ik1hQtRFWJVuDPwk5ghiPHxwIYLd+cRFHiHsT96isWzNJTiDinWpN/5XKkE5QfTe
637KaJc4tGJebEG1LhsgtUTxbTImCPxYvKUItDlApOusVvhARjqCnXunNEu5iDiADHH
638Wsv3eSPdWkdF5Jjgt/bI4I9XmagX3e1z6ZQiGvdBwCc8ccwkU6yTswXgWCPqyw/t
639lbTFqE19lEoHGTYYElKaHUo9hCmI3HZS69ShYKG7dMT9dVLhzRlNx7AzZcYWh8Mx
640Ptc8OY0CgYEA1LJe5EpfJ/XvzbiVtNiq07CGhlQj62DAH+XpyqtWHHrUNgMbnBZS
64129had9h2NyfIFDIZAKPGWRuSB6PSyDR6w5Sugh5nRoXshzaFr1pAHmo18s+QELjj
642XyccwivxRXurwmdDL5Bx0YCKII4LJyE3CBlJzq0/wOxvi+iKDRG+TIUCgYEAyDG8
643DXk+E6f9Vd4phaN3sLVDd228U/NNuEr+K74AFHwomgEv//KdK2i/EjFq0zGf31jE
644QMoVbnTDmmzVPfKRDlD3tk5XIz2TDzgGxOYBIWJLUiOlkXxckbLVJBR3NxKn561n
645id7vMR8ik+hAhEp9yZishZr+QrS/4AyHR3ahBRUCgYBYgoGKboh6kJVh/lYOE7vC
646q8rPS2RHJtPMclh/xhznbRWyBEkRAxkn8zhydtl6ykswXEibQ4veuOJj24BzX6NW
647kCCudQh1CHYNLlsjRWM5ROl+SXGiA85aYmRNSQv15ijrlR0YRfuXOu4/7dwmRGQq
648MpvMLbxCBCHHDtWj6qZOIQKBgF+3F7hBbaKsQP2bGLMicwlzwOwK9W4V9+TTRi7X
649yuYAbtEjHDX9Y5Prot8p7W9IXK3GnR51AEYtYZAl1NancR8tKyJo1lStDfDK0sG1
650TnkNrAF7tZ+XnBK1NB7qAg28x7aHO+e5RRdxUXDyLFaT3wxSCLpgXoy6KrsOgmdy
651mo35An9pYQ3Ik9ghh3PJsQ0r/TywuKIzmSvLJZfI/cuBOFkPDoWCleQGdzyQcxuc
652PSCtw8eXUj/Oc09qo5dRWXQkt5uW8sJB0k5fNnfCDqNReUXavDNXOHq31J5USy5R
6538ts1bmtZtK0oRci6A8PcgWChUvSfFUT5IrQM/x4rxabn8qIK
654-----END RSA PRIVATE KEY-----
655"#;
656
657 const PKCS8_PEM: &str = r#"-----BEGIN PRIVATE KEY-----
658MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDXxo5+n7aZ0psn
659dNjs53za9Af657AuG3sVnvWEBf24OvwwWClJ5vN+cWA7V2yIuuVvd40RxX1N4HLX
660QewaUBVw+XlHanskcYA8WTVuMTI6XNY6hIAtU1ETSWAPke5sH6DyrAzxIoC2R+IH
661ejqwjtdWdQ0MNVudqY3BO6mAH+zYblRzytMmcols+aqYNgZeAYuEie+EiJiTT65v
662y0mG24k0ALF5XLPahxhoUK/xuhjjG/Y/InD8s6C4BksO29bStnyqhMToSGMtUyOT
663PTyh1XgrUB4dlfEnpfX9F/wU8a7ijrD38Qtg935c08Qg9YcwVXzpFHWRw/ZF/auq
664lcazbMaHAgMBAAECggEAOKmhncrfLsHJkLD0jjGz7eOLfO3+q/z3c5QMsSDJoemL
665dD6SiR+m7ZtkQ/EPRVCfE4h3eSU9ZIf+YFylXbuOBd7dZE2oDMfpfu+GQmuU3xKm
666BzPoXP62GbR5D12pGKetokxgEaqX1kZGKuSEKP05uzB9vqj8aAiwev/p4QWBMsw6
6672stumeWMuZortwL9PZpXgzpJPHXDnFdsn3OIINBMFYFdqda8RhL3rWWsbV5nL1oR
668Q2/SMPLc1dQ8ZQKdPmbVhdfnPitVKVEkn8xIiFPWNS3SfYIi+wQj0lWdJbvUUJ1i
6697BIXvnXeeVLyYhekTpE5ZnGeGI4A5lix4PN+GIao8QKBgQDtuPW8BaXWfPHb93Kl
670mWBQNHz0I71p8GL9/+xRpA9SMuUtYS0jJ1whNgcwoSI4cOKo1UsIMDPAPpTU47Ul
6710D+vXr/GyiONL6+IsXAf5xhaQnUWRWKs4G9obadyGkT8aH6y8W+ddKD1JWQKUf4t
672Bmpeim+Ck0I8POhDbNNfThTLwwKBgQDoXZ70Pb6HViZAbzf+rEznNycgG8IqtTSc
673V7YoSMZe17u0AQjE9XZizBrhpz47N6/JvyYTBIh6VPQe880FTnHdUjvbqn8bmLE7
674QEYwvgF5hmHVXlWXUsyKbfMH5Dp8Uy74FV2VTd1hJ7UMSke7LQT41Hgyaz32x7Lm
675r0P63fgh7QKBgQDMrnCGz6YWo8XrS4efJgxTgp4D57HzQVM6t9xV/xhiAghppj4j
676AoTE46wVJug8CJZgICZWiopEgJ3NH7KdOE1dRguBshIiQmi1HXIZRfUl4grGfj+T
6778jp6g8+k4xF68s4EbPVZcU4VRXh5mldrlRaJCFEy8HAbRaYGR/FHIget2QKBgGd/
678o9h4VBAmAD29DDzkdBCc0VGM66xoL/nfW6SP3cPK5bFksIpCJywUa3jNLHvl7ue2
679u3fHEh8jDeVnhI9zhGYnRcAvLhSVq4OPunPlffSqNZN7RDZ1y+Nw28pNDvvndUlN
680AvUIzK2EqTDDOTYW9Fr9EFisydnM01PLB0WLbwV1AoGAGmaWcbNfPyPnJU1nIHGG
681fPlEpGn+3Oxr1ja02FPwexk/bg6CRVIqP2x7RtR1cH9fOqiDOoIqyfKswuZkwVj3
682EMeos/WHHrw+UzXem+IswmwG9rnUBMlMRCkJ9GhXk98bqoWeJpMhlj1L+oBQ3Spj
683j8T1spkdY4jj3CvmzQ0ha0U=
684-----END PRIVATE KEY-----
685"#;
686}