xref: /aosp_15_r20/tools/security/remote_provisioning/hwtrust/src/publickey.rs (revision d9ecfb0f4d734c9ce41cde8ac4d585b094fd4222)
1 //! This module describes a public key that is restricted to one of the supported algorithms.
2 
3 use anyhow::{ensure, Context, Result};
4 use openssl::hash::MessageDigest;
5 use openssl::nid::Nid;
6 use openssl::pkey::{HasParams, Id, PKey, PKeyRef, Public};
7 use openssl::sign::Verifier;
8 use std::error::Error;
9 use std::fmt;
10 
11 /// The kinds of digital signature keys that are supported.
12 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
13 pub(crate) enum SignatureKind {
14     Ed25519,
15     Ec(EcKind),
16 }
17 
18 /// The kinds of key agreement keys that are supported.
19 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
20 pub(crate) enum KeyAgreementKind {
21     X25519,
22     Ec(EcKind),
23 }
24 
25 /// Enumeration of the kinds of elliptic curve keys that are supported.
26 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
27 pub(crate) enum EcKind {
28     P256,
29     P384,
30 }
31 
32 // Wraps PKey<Public> so we can implement some traits around it, allowing for derived traits on
33 // types that include a PKey<Public>.
34 #[derive(Clone)]
35 struct PKeyPublicWrapper(PKey<Public>);
36 
37 /// Public key used for signature validation.
38 #[derive(Clone, Debug, Eq, PartialEq)]
39 pub struct PublicKey {
40     kind: SignatureKind,
41     pkey: PKeyPublicWrapper,
42 }
43 
44 /// Public key used for key agreement.
45 #[derive(Clone, Debug, Eq, PartialEq)]
46 pub struct KeyAgreementPublicKey {
47     kind: KeyAgreementKind,
48     pkey: PKeyPublicWrapper,
49 }
50 
51 impl PublicKey {
kind(&self) -> SignatureKind52     pub(crate) fn kind(&self) -> SignatureKind {
53         self.kind
54     }
55 
pkey(&self) -> &PKeyRef<Public>56     pub(crate) fn pkey(&self) -> &PKeyRef<Public> {
57         &self.pkey.0
58     }
59 
60     /// Verify that the signature obtained from signing the given message
61     /// with the PublicKey matches the signature provided.
verify(&self, signature: &[u8], message: &[u8]) -> Result<()>62     pub fn verify(&self, signature: &[u8], message: &[u8]) -> Result<()> {
63         let mut verifier = match self.kind {
64             SignatureKind::Ed25519 => Verifier::new_without_digest(&self.pkey.0),
65             SignatureKind::Ec(ec) => Verifier::new(digest_for_ec(ec), &self.pkey.0),
66         }
67         .with_context(|| format!("Failed to create verifier {:?}", self.kind))?;
68         let verified =
69             verifier.verify_oneshot(signature, message).context("Failed to verify signature")?;
70         ensure!(verified, "Signature verification failed.");
71         Ok(())
72     }
73 
74     /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure.
to_pem(&self) -> String75     pub fn to_pem(&self) -> String {
76         self.pkey.to_pem()
77     }
78 
pkey_kind<T: HasParams>(pkey: &PKeyRef<T>) -> Option<SignatureKind>79     fn pkey_kind<T: HasParams>(pkey: &PKeyRef<T>) -> Option<SignatureKind> {
80         match pkey.id() {
81             Id::ED25519 => Some(SignatureKind::Ed25519),
82             Id::EC => pkey_ec_kind(pkey).map(SignatureKind::Ec),
83             _ => None,
84         }
85     }
86 }
87 
88 impl KeyAgreementPublicKey {
pkey(&self) -> &PKeyRef<Public>89     pub(crate) fn pkey(&self) -> &PKeyRef<Public> {
90         &self.pkey.0
91     }
92 
93     /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure.
to_pem(&self) -> String94     pub fn to_pem(&self) -> String {
95         self.pkey.to_pem()
96     }
97 
pkey_kind(pkey: &PKeyRef<Public>) -> Option<KeyAgreementKind>98     fn pkey_kind(pkey: &PKeyRef<Public>) -> Option<KeyAgreementKind> {
99         match pkey.id() {
100             Id::X25519 => Some(KeyAgreementKind::X25519),
101             Id::EC => pkey_ec_kind(pkey).map(KeyAgreementKind::Ec),
102             _ => None,
103         }
104     }
105 }
106 
107 impl Eq for PKeyPublicWrapper {}
108 
109 impl PartialEq for PKeyPublicWrapper {
eq(&self, rhs: &PKeyPublicWrapper) -> bool110     fn eq(&self, rhs: &PKeyPublicWrapper) -> bool {
111         self.0.public_eq(&rhs.0)
112     }
113 }
114 
115 impl PKeyPublicWrapper {
to_pem(&self) -> String116     fn to_pem(&self) -> String {
117         String::from_utf8(self.0.public_key_to_pem().unwrap()).unwrap()
118     }
119 }
120 
121 impl fmt::Debug for PKeyPublicWrapper {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result122     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
123         fmt.write_str(&self.to_pem())
124     }
125 }
126 
127 /// The error type returned when converting from [`PKey'] to [`PublicKey`] fails.
128 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
129 pub struct TryFromPKeyError(());
130 
131 impl fmt::Display for TryFromPKeyError {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result132     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
133         write!(fmt, "unsupported public key conversion attempted")
134     }
135 }
136 
137 impl Error for TryFromPKeyError {}
138 
139 impl TryFrom<PKey<Public>> for PublicKey {
140     type Error = TryFromPKeyError;
141 
try_from(pkey: PKey<Public>) -> Result<Self, Self::Error>142     fn try_from(pkey: PKey<Public>) -> Result<Self, Self::Error> {
143         let kind = PublicKey::pkey_kind(&pkey).ok_or(TryFromPKeyError(()))?;
144         Ok(Self { kind, pkey: PKeyPublicWrapper(pkey) })
145     }
146 }
147 
148 impl TryFrom<PKey<Public>> for KeyAgreementPublicKey {
149     type Error = TryFromPKeyError;
150 
try_from(pkey: PKey<Public>) -> Result<Self, Self::Error>151     fn try_from(pkey: PKey<Public>) -> Result<Self, Self::Error> {
152         let kind = KeyAgreementPublicKey::pkey_kind(&pkey).ok_or(TryFromPKeyError(()))?;
153         Ok(Self { kind, pkey: PKeyPublicWrapper(pkey) })
154     }
155 }
156 
pkey_ec_kind<T: HasParams>(pkey: &PKeyRef<T>) -> Option<EcKind>157 fn pkey_ec_kind<T: HasParams>(pkey: &PKeyRef<T>) -> Option<EcKind> {
158     match pkey.id() {
159         Id::EC => match pkey.ec_key().unwrap().group().curve_name() {
160             Some(Nid::X9_62_PRIME256V1) => Some(EcKind::P256),
161             Some(Nid::SECP384R1) => Some(EcKind::P384),
162             _ => None,
163         },
164         _ => None,
165     }
166 }
167 
digest_for_ec(ec: EcKind) -> MessageDigest168 fn digest_for_ec(ec: EcKind) -> MessageDigest {
169     match ec {
170         EcKind::P256 => MessageDigest::sha256(),
171         EcKind::P384 => MessageDigest::sha384(),
172     }
173 }
174 
175 #[cfg(test)]
176 mod tests {
177     use super::*;
178 
179     #[test]
from_ed25519_pkey()180     fn from_ed25519_pkey() {
181         let pkey = load_public_pkey(testkeys::ED25519_KEY_PEM[0]);
182         let key: PublicKey = pkey.clone().try_into().unwrap();
183         assert_eq!(key.kind, SignatureKind::Ed25519);
184         assert_eq!(key.to_pem().as_bytes(), pkey.public_key_to_pem().unwrap());
185     }
186 
187     #[test]
from_p256_pkey()188     fn from_p256_pkey() {
189         let pkey = load_public_pkey(testkeys::P256_KEY_PEM[0]);
190         let key: PublicKey = pkey.clone().try_into().unwrap();
191         assert_eq!(key.kind, SignatureKind::Ec(EcKind::P256));
192         assert_eq!(key.to_pem().as_bytes(), pkey.public_key_to_pem().unwrap());
193     }
194 
195     #[test]
from_p384_pkey()196     fn from_p384_pkey() {
197         let pkey = load_public_pkey(testkeys::P384_KEY_PEM[0]);
198         let key: PublicKey = pkey.clone().try_into().unwrap();
199         assert_eq!(key.kind, SignatureKind::Ec(EcKind::P384));
200         assert_eq!(key.to_pem().as_bytes(), pkey.public_key_to_pem().unwrap());
201     }
202 
203     #[test]
from_p521_pkey_not_supported()204     fn from_p521_pkey_not_supported() {
205         let pkey = load_public_pkey(testkeys::P521_KEY_PEM[0]);
206         assert!(PublicKey::try_from(pkey).is_err());
207     }
208 
209     #[test]
from_rsa2048_pkey_not_supported()210     fn from_rsa2048_pkey_not_supported() {
211         let pkey = load_public_pkey(testkeys::RSA2048_KEY_PEM[0]);
212         assert!(PublicKey::try_from(pkey).is_err());
213     }
214 
215     #[test]
from_x25519_pkey_not_supported()216     fn from_x25519_pkey_not_supported() {
217         let pkey = load_public_pkey(testkeys::X25519_KEY_PEM[0]);
218         assert!(PublicKey::try_from(pkey).is_err());
219     }
220 
221     #[test]
key_agreement_key_from_x25519_pkey()222     fn key_agreement_key_from_x25519_pkey() {
223         let pkey = load_public_pkey(testkeys::X25519_KEY_PEM[0]);
224         let key: KeyAgreementPublicKey = pkey.clone().try_into().unwrap();
225         assert_eq!(key.kind, KeyAgreementKind::X25519);
226         assert_eq!(key.to_pem().as_bytes(), pkey.public_key_to_pem().unwrap());
227     }
228 
229     #[test]
key_agreement_key_from_p256_pkey()230     fn key_agreement_key_from_p256_pkey() {
231         let pkey = load_public_pkey(testkeys::P256_KEY_PEM[0]);
232         let key: KeyAgreementPublicKey = pkey.clone().try_into().unwrap();
233         assert_eq!(key.kind, KeyAgreementKind::Ec(EcKind::P256));
234         assert_eq!(key.to_pem().as_bytes(), pkey.public_key_to_pem().unwrap());
235     }
236 
237     #[test]
key_agreement_key_from_p384_pkey()238     fn key_agreement_key_from_p384_pkey() {
239         let pkey = load_public_pkey(testkeys::P384_KEY_PEM[0]);
240         let key: KeyAgreementPublicKey = pkey.clone().try_into().unwrap();
241         assert_eq!(key.kind, KeyAgreementKind::Ec(EcKind::P384));
242         assert_eq!(key.to_pem().as_bytes(), pkey.public_key_to_pem().unwrap());
243     }
244 
245     #[test]
key_agreement_key_from_ed25519_pkey_not_supported()246     fn key_agreement_key_from_ed25519_pkey_not_supported() {
247         let pkey = load_public_pkey(testkeys::ED25519_KEY_PEM[0]);
248         assert!(KeyAgreementPublicKey::try_from(pkey).is_err());
249     }
250 
load_public_pkey(pem: &str) -> PKey<Public>251     pub fn load_public_pkey(pem: &str) -> PKey<Public> {
252         testkeys::public_from_private(&PKey::private_key_from_pem(pem.as_bytes()).unwrap())
253     }
254 
255     #[test]
verify_pkey_equality()256     fn verify_pkey_equality() {
257         let first = PKeyPublicWrapper(load_public_pkey(testkeys::ED25519_KEY_PEM[0]));
258         let second = PKeyPublicWrapper(load_public_pkey(testkeys::ED25519_KEY_PEM[0]));
259         assert_eq!(&first, &first);
260         assert_eq!(&first, &second);
261         assert_eq!(&second, &first);
262     }
263 
264     #[test]
verify_key_kind_inequality()265     fn verify_key_kind_inequality() {
266         let ed25519 = PKeyPublicWrapper(load_public_pkey(testkeys::ED25519_KEY_PEM[0]));
267         let p256 = PKeyPublicWrapper(load_public_pkey(testkeys::P256_KEY_PEM[0]));
268         assert_ne!(&ed25519, &p256);
269         assert_ne!(&p256, &ed25519);
270     }
271 
272     #[test]
verify_key_bits_inequality()273     fn verify_key_bits_inequality() {
274         let first = PKeyPublicWrapper(load_public_pkey(testkeys::P256_KEY_PEM[0]));
275         let second = PKeyPublicWrapper(load_public_pkey(testkeys::P256_KEY_PEM[1]));
276         assert_ne!(&first, &second);
277         assert_ne!(&second, &first);
278     }
279 }
280 
281 /// Keys and key handling utilities for use in tests.
282 #[cfg(test)]
283 pub(crate) mod testkeys {
284     use super::*;
285     use openssl::pkey::Private;
286     use openssl::sign::Signer;
287 
288     pub struct PrivateKey {
289         kind: SignatureKind,
290         pkey: PKey<Private>,
291     }
292 
293     impl PrivateKey {
from_pem(pem: &str) -> Self294         pub fn from_pem(pem: &str) -> Self {
295             let pkey = PKey::private_key_from_pem(pem.as_bytes()).unwrap();
296             let kind = PublicKey::pkey_kind(&pkey).expect("unsupported private key");
297             Self { kind, pkey }
298         }
299 
kind(&self) -> SignatureKind300         pub(crate) fn kind(&self) -> SignatureKind {
301             self.kind
302         }
303 
public_key(&self) -> PublicKey304         pub fn public_key(&self) -> PublicKey {
305             public_from_private(&self.pkey).try_into().unwrap()
306         }
307 
sign(&self, message: &[u8]) -> Result<Vec<u8>>308         pub fn sign(&self, message: &[u8]) -> Result<Vec<u8>> {
309             let mut signer = match self.kind {
310                 SignatureKind::Ed25519 => Signer::new_without_digest(&self.pkey)?,
311                 SignatureKind::Ec(ec) => Signer::new(digest_for_ec(ec), &self.pkey)?,
312             };
313             signer.sign_oneshot_to_vec(message).context("signing message")
314         }
315     }
316 
317     /// Gives the public key that matches the private key.
public_from_private(pkey: &PKey<Private>) -> PKey<Public>318     pub fn public_from_private(pkey: &PKey<Private>) -> PKey<Public> {
319         // It feels like there should be a more direct way to do this but I haven't found it.
320         PKey::public_key_from_der(&pkey.public_key_to_der().unwrap()).unwrap()
321     }
322 
323     /// A selection of X25519 private keys.
324     pub const X25519_KEY_PEM: &[&str] = &["-----BEGIN PRIVATE KEY-----\n\
325         MC4CAQAwBQYDK2VuBCIEIMDLdDFad6CwwacwNtW/kQujlrAkxIjQ/Co3DleSd9xV\n\
326         -----END PRIVATE KEY-----\n"];
327 
328     /// A selection of Ed25519 private keys.
329     pub const ED25519_KEY_PEM: &[&str] = &["-----BEGIN PRIVATE KEY-----\n\
330         MC4CAQAwBQYDK2VwBCIEILKW0KEeuieFxhDAzigQPE4XRTiQx+0/AlAjJqHmUWE6\n\
331         -----END PRIVATE KEY-----\n"];
332 
333     pub const ED25519_KEY_WITH_LEADING_ZEROS_PEM: &[&str] = &["-----BEGIN PRIVATE KEY-----\n\
334         MC4CAQAwBQYDK2VwBCIEIBDTK4d0dffOye5RD6HsgcOFoDTtvQH1tPmr9RjpadxJ\n\
335         -----END PRIVATE KEY-----\n"];
336 
337     /// A selection of elliptic curve P-256 private keys.
338     pub const P256_KEY_PEM: &[&str] = &[
339         "-----BEGIN PRIVATE KEY-----\n\
340         MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg+CO3ZBuAsimwPKAL\n\
341         IeDyCh4cRZ5EMd6llGu5MQCpibGhRANCAAQObPxc4bIPjupILrvKJjTrpTcyCf6q\n\
342         V552FlS67fGphwhg2LDfQ8adEdkuRfQvk+IvKJz8MDcPjErBG3Wlps1N\n\
343         -----END PRIVATE KEY-----\n",
344         "-----BEGIN PRIVATE KEY-----\n\
345         MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgw1OPIcfQv5twO68B\n\
346         H+xNstW3DLXC6e4PGEYG/VppYVahRANCAAQMyWyv4ffVMu+wVNhNEk2mQSaTmSl/\n\
347         dLdRbEowfqPwMzdqdQ3QlKSV4ZcU2lsJEuQMkZzmVPz02enY2qcKctmj\n\
348         -----END PRIVATE KEY-----\n",
349         "-----BEGIN PRIVATE KEY-----\n\
350         MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgbXO6ee7i7sY4YfFS\n\
351         Gn60ScPuL3QuYFMX4nJbcqPSQ7+hRANCAAS8i9xA8cIcWStbMG97YrttQsYEIR2a\n\
352         15+alxbb6b7422FuxBB0qG5nJ4m+Jd3Bp+N2lwx4rHBFDqU4cp8VlQav\n\
353         -----END PRIVATE KEY-----\n",
354         "-----BEGIN PRIVATE KEY-----\n\
355         MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/JuxkbpPyyouat11\n\
356         szDR+OA7d/fuMk9IhGkH7z1xHzChRANCAASRlY0D7Uh5T/FmB6txGr21w6jqKW2x\n\
357         RXdsaZgCB6XnrXlkgkvuWDc0CTLSBWdPFgW6OX0fyXViglEBH95REyQr\n\
358         -----END PRIVATE KEY-----\n",
359     ];
360 
361     /// A selection of EC keys that should have leading zeros in their coordinates
362     pub const EC2_KEY_WITH_LEADING_ZEROS_PEM: &[&str] = &[
363         // P256
364         // Public key has Y coordinate with most significant byte of 0x00
365         "-----BEGIN PRIVATE KEY-----\n\
366         MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCWbRSB3imI03F5YNVq\n\
367         8AN8ZbyzW/h+5BQ53caD5VkWJg==\n\
368         -----END PRIVATE KEY-----\n",
369         // P256
370         // Public key has X coordinate with most significant byte of 0x00
371         "-----BEGIN PRIVATE KEY-----\n\
372         MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCDe5E5WqNmCLxtsCNTc\n\
373         UOb9CPXCn6l3CZpbrp0aivb+Bw==\n\
374         -----END PRIVATE KEY-----\n",
375         // P384
376         // Public key has Y coordinate with most significant byte of 0x00
377         "-----BEGIN PRIVATE KEY-----\n\
378         ME4CAQAwEAYHKoZIzj0CAQYFK4EEACIENzA1AgEBBDCzgVHCz7wgmSdb7/IixYik\n\
379         3AuQceCtBTiFrJpgpGFluwgLUR0S2NpzIuty4M7xU74=\n\
380         -----END PRIVATE KEY-----\n",
381         // P384
382         // Public key has X coordinate with most significant byte of 0x00
383         "-----BEGIN PRIVATE KEY-----\n\
384         ME4CAQAwEAYHKoZIzj0CAQYFK4EEACIENzA1AgEBBDBoW+8zbvwf5fYOS8YPyPEH\n\
385         jHP71Vr1MnRYRp/yG1wbthW2XEu0UWbp4qrZ5WTnZPg=\n\
386         -----END PRIVATE KEY-----\n",
387     ];
388     pub const EC2_KEY_WITH_HIGH_BITS_SET_PEM: &[&str] = &[
389         // P256
390         // Public key has X & Y coordinate that both have most significant bit set,
391         // and some stacks will add a padding byte
392         "-----BEGIN PRIVATE KEY-----\n\
393         MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCWOWcXPDEVZ4Qz3EBK\n\
394         uvSqhD9HmxDGxcNe3yxKi9pazw==\n\
395         -----END PRIVATE KEY-----\n",
396         // P384
397         // Public key has X & Y coordinate that both have most significant bit set,
398         // and some stacks will add a padding byte
399         "-----BEGIN PRIVATE KEY-----\n\
400         ME4CAQAwEAYHKoZIzj0CAQYFK4EEACIENzA1AgEBBDD2A69j5M/6oc6/WGoYln4t\n\
401         Alnn0C6kpJz1EVC+eH6y0YNrcGamz8pPY4NkzUB/tj4=\n\
402         -----END PRIVATE KEY-----\n",
403     ];
404 
405     /// A selection of elliptic curve P-384 private keys.
406     pub const P384_KEY_PEM: &[&str] = &["-----BEGIN PRIVATE KEY-----\n\
407         MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBMZ414LiUpcuNTNq5W\n\
408         Ig/qbnbFn0MpuZZxUn5YZ8/+2/tyXFFHRyQoQ4YpNN1P/+qhZANiAAScPDyisb21\n\
409         GldmGksI5g82hjPRYscWNs/6pFxQTMcxABE+/1lWaryLR193ZD74VxVRIKDBluRs\n\
410         uuHi+VayOreTX1/qlUoxgBT+XTI0nTdLn6WwO6vVO1NIkGEVnYvB2eM=\n\
411         -----END PRIVATE KEY-----\n"];
412 
413     /// A selection of elliptic curve P-521 private keys.
414     pub const P521_KEY_PEM: &[&str] = &["-----BEGIN PRIVATE KEY-----\n\
415         MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIBQuD8Db3jT2yPYR5t\n\
416         Y1ZqESxOe4eBWzekFKg7cjVWsSiJEvWTPC1H7CLtXQBHZglO90dwMt4flL91xHkl\n\
417         iZOzyHahgYkDgYYABAHACwmmKkZu01fp1QTTTQ0cv7IAfYv9FEBz8yfhNGPnI2WY\n\
418         iH1/lYeCfYc9d33aSc/ELY9+vIFzVStJumS/B/WTewEhxVomlKPAkUJeLdCaK5av\n\
419         nlUNj7pNQ/5v5FZVxmoFJvAtUAnZqnJqo/QkLtEnmKlzpLte2LuwTPZhG35z0HeL\n\
420         2g==\n\
421         -----END PRIVATE KEY-----\n"];
422 
423     /// A selection of 2048-bit RSA private keys.
424     pub const RSA2048_KEY_PEM: &[&str] = &["-----BEGIN PRIVATE KEY-----\n\
425         MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDbOJh7Ys7CuIju\n\
426         VVKMlFlZWwDEGBX5bVYD/xNBNNF1FY9bOcV/BG20IwoZkdV0N+vm8eWSuv/uwIJp\n\
427         sN2PMWPAEIWbPGGMnSdePpkwrdpFFywhEQqUrfdCFXZ8zeF85Nz5mL8ysl4vlMsL\n\
428         mbErCkrq++K0lzs+k7w/FtPCgs4M3WypJfZef5zM0CGWxpHZGoUGm0HW9fen4sv8\n\
429         hTmMGNY/r0SJhdZREGmiGCx2v+ksOEBon1r/6QKVTP8S73XFsyNCWyop0hYTakut\n\
430         D3HtJ5sWzu2RU8rrch3Txinz0jpGF8PATHk35YMw/9jwwwSqjDw+pOQcYk8SviAf\n\
431         glZf8aZlAgMBAAECggEAAS67PK67tuaOWywJSWHLsWGmqJ4I2tZiTzCT9EZ2MOVx\n\
432         +4ZChNfjHUsskXUp4XNL/FE0J3WvhEYjXR1u+L37nvqc48mJpjoPN7o/CMb6rM/J\n\
433         +ly9A2ZOvEB4ppOYDYh5QVDm7/otmvEMzJxuUOpvxYxqnJpAPgl9dBpNQ0nSt3YX\n\
434         jJS4+vuzQpwwSTfchpcCZYU3AX9DpQpxnrLX3/7d3GTs2NuedmSwRz+mCfwaOlFk\n\
435         jdrJ2uJJrDLcK6yhSdsE9aNgKkmX6aNLhxbbCFTyDNiGY5HHayyL3mVvyaeovYcn\n\
436         ZS+Z+0TJGCgXDRHHSFyIAsgVonxHfn49x9uvfpuMFQKBgQD2cVp26+aQgt46ajVv\n\
437         yn4fxbNpfovL0pgtSjo7ekZOWYJ3Is1SDmnni8k1ViKgUYC210dTTlrljxUil8T0\n\
438         83e03k2xasDi2c+h/7JFYJPDyZwIm1o19ciUwY73D54iJaRbrzEximFeA0h4LGKw\n\
439         Yjd4xkKMJw16CU00gInyI193BwKBgQDjuP0/QEEPpYvzpag5Ul4+h22K/tiOUrFj\n\
440         NuSgd+IvQG1hW48zHEa9vXvORQ/FteiQ708racz6ByqY+n2w6QdtdRMj7Hsyo2fk\n\
441         SEeNaLrR7Sif6MfkYajbSGFySDD82vj4Jt76vzdt3MjpZfs6ryPmnKLVPWNA3mnS\n\
442         4+u2J/+QMwKBgFfiJnugNnG0aaF1PKcoFAAqlYd6XEoMSL5l6QxK14WbP/5SR9wK\n\
443         TdQHsnI1zFVVm0wYy1O27o1MkCHs84zSwg6a9CPfyPdc60F/GMjK3wcD/4PGOs5h\n\
444         Xu1FdUE/rYnJ2KnleOqMyZooG5DXaz4xWEzWjubCCnlJleGyMP9LhADDAoGAR/jK\n\
445         iXgcV/6haeMcdOl0gdy5oWmENg8qo0nRHmplYTvCljei3at9LDC79WhcYMdqdow8\n\
446         AGOS9h7XtrvMh+JOh6it4Pe3xDxi9IJnoujLytditI+Uxbib7ppEuiLY4MGwWHWo\n\
447         maVftmhGU4X4zgZWmWc+C5k4SmNBHPcOI2cm3YMCgYB5/Ni+tBxng0S/PRAtwCeG\n\
448         dVnQnYvS2C5nHCn9D5rmAcVXUKrIJ1/1K4se8vQ15DDcpuBF1SejYTJzdUP8Zgcs\n\
449         p8wVq7neK8uSsmG+AfUgxMjbetoAVTP3L8+GbjocznR9auB7BEjFVO25iYSiTp/w\n\
450         NNzbIKQRDN+c3vUpneJcuw==\n\
451         -----END PRIVATE KEY-----\n"];
452 }
453