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