From 6c8231562c7bb31a94a6f4906b0ec3557265ea37 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Tue, 19 May 2026 19:35:17 +0100 Subject: [PATCH 1/2] Fix test_kdf.rb in FIPS. * PBKDF2 salt >= 16 bytes (128 bits) and iterations >= 1000 are required in FIPS. SP 800-132: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf * 5.1 The Salt (S) https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/providers/implementations/kdfs/pbkdf2.c#L235-L240 * 5.2 The Iteration Count (C) https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/providers/implementations/kdfs/pbkdf2.c#L247-L252 * scrypt (RFC 7914) is not available in FIPS. EVP_KDF_fetch(ctx, OSSL_KDF_NAME_SCRYPT, propq) returns NULL in FIPS. https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/crypto/evp/pbe_scrypt.c#L67-L71 * Omit test_hkdf_rfc5869_test_case_4 in FIPS, as the used key length 88 bits is less than the minimal key length 112 bits. * Add test_hkdf_rfc5869_test_case_5 as a complemental test in FIPS. --- Rakefile | 1 - test/openssl/test_kdf.rb | 81 +++++++++++++++++++++++++++++++++++----- 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/Rakefile b/Rakefile index 69256bd63..ff187f07f 100644 --- a/Rakefile +++ b/Rakefile @@ -26,7 +26,6 @@ Rake::TestTask.new(:test_fips_internal) do |t| # Exclude failing test files in FIPS for this task to pass. # TODO: Fix failing test files. t.test_files = FileList['test/**/test_*.rb'] - FileList[ - 'test/openssl/test_kdf.rb', 'test/openssl/test_ts.rb', ] t.warning = true diff --git a/test/openssl/test_kdf.rb b/test/openssl/test_kdf.rb index 6a12a25aa..1b28ae40e 100644 --- a/test/openssl/test_kdf.rb +++ b/test/openssl/test_kdf.rb @@ -5,12 +5,24 @@ class OpenSSL::TestKDF < OpenSSL::TestCase def test_pkcs5_pbkdf2_hmac_compatibility - expected = OpenSSL::KDF.pbkdf2_hmac("password", salt: "salt", iterations: 1, length: 20, hash: "sha1") - assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac("password", "salt", 1, 20, "sha1")) - assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac_sha1("password", "salt", 1, 20)) + # PBKDF2 salt >= 16 bytes (128 bits) and iterations >= 1000 are required in + # FIPS. + # SP 800-132. + # https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf + # * 5.1 The Salt (S) + # * 5.2 The Iteration Count (C) + # https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/providers/implementations/kdfs/pbkdf2.c#L235-L240 + # https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/providers/implementations/kdfs/pbkdf2.c#L247-L252 + expected = OpenSSL::KDF.pbkdf2_hmac("password", salt: "salt567890123456", iterations: 1000, length: 20, hash: "sha1") + assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac("password", "salt567890123456", 1000, 20, "sha1")) + assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac_sha1("password", "salt567890123456", 1000, 20)) end def test_pbkdf2_hmac_sha1_rfc6070_c_1_len_20 + # PBKDF2 salt >= 16 bytes (128 bits) and iterations >= 1000 are required in + # FIPS. + omit_on_fips + p ="password" s = "salt" c = 1 @@ -24,6 +36,10 @@ def test_pbkdf2_hmac_sha1_rfc6070_c_1_len_20 end def test_pbkdf2_hmac_sha1_rfc6070_c_2_len_20 + # PBKDF2 salt >= 16 bytes (128 bits) and iterations >= 1000 are required in + # FIPS. + omit_on_fips + p ="password" s = "salt" c = 2 @@ -38,12 +54,12 @@ def test_pbkdf2_hmac_sha1_rfc6070_c_2_len_20 def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_20 p ="password" - s = "salt" + s = "salt567890123456" c = 4096 dk_len = 20 - raw = %w{ 4b 00 79 01 b7 65 48 9a - be ad 49 d9 26 f7 21 d0 - 65 a4 29 c1 } + raw = %w{ ff 9a a6 35 94 73 b8 98 + cc 3a 8b e9 82 ff 6b 2a + d6 33 2a 52 } expected = [raw.join('')].pack('H*') value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") assert_equal(expected, value) @@ -80,11 +96,11 @@ def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_25 def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_16 p ="pass\0word" - s = "sa\0lt" + s = "sa\0lt567890123456" c = 4096 dk_len = 16 - raw = %w{ 56 fa 6a a7 55 48 09 9d - cc 37 d7 f0 34 25 e0 c3 } + raw = %w{ cd c3 ad 7f 78 2b 96 48 + d9 07 6f 5c 14 70 9f e5 } expected = [raw.join('')].pack('H*') value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") assert_equal(expected, value) @@ -103,6 +119,11 @@ def test_pbkdf2_hmac_sha256_c_20000_len_32 def test_scrypt_rfc7914_first pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0 + # scrypt is not available in FIPS. + # EVP_KDF_fetch(ctx, OSSL_KDF_NAME_SCRYPT, propq) returns NULL in FIPS. + # https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/crypto/evp/pbe_scrypt.c#L67-L71 + omit_on_fips + pass = "" salt = "" n = 16 @@ -118,6 +139,9 @@ def test_scrypt_rfc7914_first def test_scrypt_rfc7914_second pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0 + # scrypt is not available in FIPS. + omit_on_fips + pass = "password" salt = "NaCl" n = 1024 @@ -131,6 +155,7 @@ def test_scrypt_rfc7914_second assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen)) end + # https://www.rfc-editor.org/rfc/rfc5869#appendix-A.1 def test_hkdf_rfc5869_test_case_1 hash = "sha256" ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") @@ -144,6 +169,7 @@ def test_hkdf_rfc5869_test_case_1 assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) end + # https://www.rfc-editor.org/rfc/rfc5869#appendix-A.3 def test_hkdf_rfc5869_test_case_3 hash = "sha256" ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") @@ -157,7 +183,13 @@ def test_hkdf_rfc5869_test_case_3 assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) end + # https://www.rfc-editor.org/rfc/rfc5869#appendix-A.4 def test_hkdf_rfc5869_test_case_4 + # FIPS requires a minimum security strength of 112 bits for key-derivation + # key (ikm). However, ikm is 11 bytes * 8 = 88 bits. + # https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/providers/common/securitycheck.c#L83 + omit_on_fips + hash = "sha1" ikm = B("0b0b0b0b0b0b0b0b0b0b0b") salt = B("000102030405060708090a0b0c") @@ -170,6 +202,35 @@ def test_hkdf_rfc5869_test_case_4 assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) end + # https://www.rfc-editor.org/rfc/rfc5869#appendix-A.5 + def test_hkdf_rfc5869_test_case_5 + hash = "sha1" + ikm = B("000102030405060708090a0b0c0d0e0f" \ + "101112131415161718191a1b1c1d1e1f" \ + "202122232425262728292a2b2c2d2e2f" \ + "303132333435363738393a3b3c3d3e3f" \ + "404142434445464748494a4b4c4d4e4f") + salt = B("606162636465666768696a6b6c6d6e6f" \ + "707172737475767778797a7b7c7d7e7f" \ + "808182838485868788898a8b8c8d8e8f" \ + "909192939495969798999a9b9c9d9e9f" \ + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf") + info = B("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" \ + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" \ + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" \ + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" \ + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff") + l = 82 + + okm = B("0bd770a74d1160f7c9f12cd5912a06eb" \ + "ff6adcae899d92191fe4305673ba2ffe" \ + "8fa3f1a4e5ad79f3f334b3b202b2173c" \ + "486ea37ce3d397ed034c7f9dfeb15c5e" \ + "927336d0441f4c4300e2cff0d0900b52" \ + "d3b4") + assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) + end + private def B(ary) From a0198e1891dfdf8c8587a58d7cf67f4af85b6d54 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Thu, 21 May 2026 15:56:46 +0100 Subject: [PATCH 2/2] Fix test_ts.rb in FIPS. 2048-bit RSA keys for intermediate_key and ee_key are required for signing and encryption in FIPS. SP 800-131A Rev. 2 * 3. Digital Signatures * 6. Key Agreement and Key Transport Using RSA https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/providers/common/securitycheck.c#L72-L73 --- Rakefile | 6 +-- test/openssl/test_ts.rb | 93 ++++++++++++++++++++++++++++------------- 2 files changed, 64 insertions(+), 35 deletions(-) diff --git a/Rakefile b/Rakefile index ff187f07f..699a7b873 100644 --- a/Rakefile +++ b/Rakefile @@ -23,11 +23,7 @@ task :test_fips => :compile do end Rake::TestTask.new(:test_fips_internal) do |t| - # Exclude failing test files in FIPS for this task to pass. - # TODO: Fix failing test files. - t.test_files = FileList['test/**/test_*.rb'] - FileList[ - 'test/openssl/test_ts.rb', - ] + t.test_files = FileList['test/**/test_*.rb'] t.warning = true end diff --git a/test/openssl/test_ts.rb b/test/openssl/test_ts.rb index cca7898bc..201208911 100644 --- a/test/openssl/test_ts.rb +++ b/test/openssl/test_ts.rb @@ -3,43 +3,76 @@ if defined?(OpenSSL) && defined?(OpenSSL::Timestamp) class OpenSSL::TestTimestamp < OpenSSL::TestCase + # 2048-bit RSA keys for intermediate_key and ee_key are required for signing + # and encryption in FIPS. + # SP 800-131A Rev. 2 + # * 3. Digital Signatures + # * 6. Key Agreement and Key Transport Using RSA + # https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf + # https://github.com/openssl/openssl/blob/71943544885ff364a10bcc5ffc62d0e651c9a021/providers/common/securitycheck.c#L72-L73 def intermediate_key @intermediate_key ||= OpenSSL::PKey::RSA.new <<-_end_of_pem_ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQCcyODxH+oTrr7l7MITWcGaYnnBma6vidCCJjuSzZpaRmXZHAyH -0YcY4ttC0BdJ4uV+cE05IySVC7tyvVfFb8gFQ6XJV+AEktP+XkLbcxZgj9d2NVu1 -ziXdI+ldXkPnMhyWpMS5E7SD6gflv9NhUYEsmAGsUgdK6LDmm2W2/4TlewIDAQAB -AoGAYgx6KDFWONLqjW3f/Sv/mGYHUNykUyDzpcD1Npyf797gqMMSzwlo3FZa2tC6 -D7n23XirwpTItvEsW9gvgMikJDPlThAeGLZ+L0UbVNNBHVxGP998Nda1kxqKvhRE -pfZCKc7PLM9ZXc6jBTmgxdcAYfVCCVUoa2mEf9Ktr3BlI4kCQQDQAM09+wHDXGKP -o2UnCwCazGtyGU2r0QCzHlh9BVY+KD2KjjhuWh86rEbdWN7hEW23Je1vXIhuM6Pa -/Ccd+XYnAkEAwPZ91PK6idEONeGQ4I3dyMKV2SbaUjfq3MDL4iIQPQPuj7QsBO/5 -3Nf9ReSUUTRFCUVwoC8k4Z1KAJhR/K/ejQJANE7PTnPuGJQGETs09+GTcFpR9uqY -FspDk8fg1ufdrVnvSAXF+TJewiGK3KU5v33jinhWQngRsyz3Wt2odKhEZwJACbjh -oicQqvzzgFd7GzVKpWDYd/ZzLY1PsgusuhoJQ2m9TVRAm4cTycLAKhNYPbcqe0sa -X5fAffWU0u7ZwqeByQJAOUAbYET4RU3iymAvAIDFj8LiQnizG9t5Ty3HXlijKQYv -y8gsvWd4CdxwOPatWpBUX9L7IXcMJmD44xXTUvpbfQ== ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9FTDnvTJvvS0w +mn/EANQKQsup5LRYEqj+aMnslI6eVBe0USC3dvjY6Bj4xkMVhVEb25L4KVSjqdnM +60IvL73P9aatFbpPJM837eHXVE25qsKzc7yxdk4covODsbd/J/jztaWEFcdoIjNd +IkuyVFo7uWlRzgboI5xHCBFBO7srimTKpICZeKslfm023J24H40GaF8+d3o0pOg/ +h5u3lYsDON9h01eWB1j2ELRelv6zeELk27AWD+jdyDOTX49aqh0PEbPEj/TeDExY +5EdiZEwGrE075rnaR1vGz4YsGZvDMX0pxlM7efextd1jy9VWAbRq8UPV2NzthopC +ZGh3EZnHAgMBAAECggEACMqd8gBxgmbaMuApdaG7j4M940yEzXLcqauR9pk3rQk9 +lZQ6FbMHQf/p/VMr66m9tN0M5H34zKfz6QZn7DgSNsOguCaCTvYSrnKLOs8AKCmr +kNrI7hARSgfnk6V6jIPSxvNuBTSwB1mjvWj/+lmCsokzP5Wj65I693CFa4eNSH+7 +1Ue8LegiWz1KEwzUwE/MoDqQ+RQxQl/cIov/8oI3lYCu0S/gO5ybylLXRNy8liVM +mZusiMe8Q8SiGD+oIUBnMgcg5MYZeYcNZuFb90xl/c4Bof0Wlyznsyyw7swlZhSm +OTIl1OleSQ1eAcvGAJc6gTpt/Q6rPvgUdzUAlYAmPQKBgQDiWD2fZVL5s7ZRKpi+ +lNSzj/UaFUZlmnjcmr4p/y+25nP/m4Q11lHyDr/zSdX4CjGMLkg5uPrnHvJ00taW +Yo2Akaqx8iT9ncF5gj18jfnHwGChEbMVhXSbvegcASPA4C7cA8gBwdX+ZQeahD6k +D5dz5vC1rbVPzz3oycWn5QVO0wKBgQDV2yjhxA/wlyes5h4OATwuNwTKctCT50yr +ZrfmbUpyXAIM4uKYLfI/zS0x9nePuTTIz8jldb68ehRNzqfw+1DCbWKBSoOlBS/u +eGGw4ni37Nm6lmCRZHMus1UZFS41/kSuA+xWV8fbzcfzNzkVvo+91n5xm48MN7K3 +SlFk8M74vQKBgQCoj5pkqCqg9qrhy10xINk+WAjqQcnJRL6ZW0wfLoG0Le9Y/dH5 +3f/syfs9DVGhhMXdZWI4Sn/fuvZI9fMEz6QdiV2bY38UuHUrLkjoBztq/ON5UBsT +/e0XRtgict7TdqCvDMnYNShOaaK9+ZpEx6+8itHcGt8Z7nZmdE0UecP4LQKBgQCk +peQ21bWT/TxNsKnpDGhiCHgGyhjuFoF/4Uiq/u/3VgE6HKBqm81L89LdCa4JmIUc +KmW4zEt6Xt8s/HNuZH9MAd16P31VWsYJauODxQk+Sftj3Y0hw12u0eEtu5Hlfgsw +ktKts02rXCaaiaTIqfuPJAobu7GJrYRJ+8zo00H2XQKBgFMm+oGbmrx6byzfFZJX +ZGukUi5vKR95KDjhLyM9Z2XHJUGj/z8a8fEMh51btI8AGKc84DS71FBsTheyrA7g +y0jEXaW4MB2AwdOW7QKaD3DjuZdWLCPDboWkoRBQY7PmRsdxF0Ve+0+xMtfJDPP8 +1d4GA0IexsTOAkPAly2/vr4g +-----END PRIVATE KEY----- _end_of_pem_ end def ee_key @ee_key ||= OpenSSL::PKey::RSA.new <<-_end_of_pem_ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQDA6eB5r2O5KOKNbKMBhzadl43lgpwqq28m+G0gH38kKCL1f3o9 -P8xUZm7sZqcWEervZMSSXMGBV9DgeoSR+U6FMJywgQGx/JNRx7wZTMNym3PvgLkl -xCXh6ZA0/xbtJtcNI+UUv0ENBkTIuUWBhkAf3jQclAr9aQ0ktYBuHAcRcQIDAQAB -AoGAKNhcAuezwZx6e18pFEXAtpVEIfgJgK9TlXi8AjUpAkrNPBWFmDpN1QDrM3p4 -nh+lEpLPW/3vqqchPqYyM4YJraMLpS3KUG+s7+m9QIia0ri2WV5Cig7WL+Tl9p7K -b3oi2Aj/wti8GfOLFQXOQQ4Ea4GoCv2Sxe0GZR39UBxzTsECQQD1zuVIwBvqU2YR -8innsoa+j4u2hulRmQO6Zgpzj5vyRYfA9uZxQ9nKbfJvzuWwUv+UzyS9RqxarqrP -5nQw5EmVAkEAyOmJg6+AfGrgvSWfSpXEds/WA/sHziCO3rE4/sd6cnDc6XcTgeMs -mT8Z3kAYGpqFDew5orUylPfJJa+PUueJbQJAY+gkvw3+Cp69FLw1lgu0wo07fwOU -n2qu3jsNMm0DOFRUWfTAMvcd9S385L7WEnWZldUfnKK1+OGXYYrMXPbchQJAChU2 -UoaHQzc16iguM1cK0g+iJPb/MEgQA3sPajHmokGpxIm2T+lvvo0dJjs/Om6QyN8X -EWRYkoNQ8/Q4lCeMjQJAfvDIGtyqF4PieFHYgluQAv5pGgYpakdc8SYyeRH9NKey -GaL27FRs4fRWf9OmxPhUVgIyGzLGXrueemvQUDHObA== ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCkQi2bnexNZipP +RM0e4VLBxd9aKzN5KZKP/k4lqDmkwhJ0GDpD440RNvwqBvP31iA44O0QBeyNMexC +djtDek61dI1jmwj3CuM4xO84AO+nrvV6sylvlxX/rEjHgQjFLlFP9uySL6faHbCn +fmy1HvL6wdS9iqbbGkjAtAHDZmb1V6GKzsIUEyC2webwrgzkUC5CePim3oY83e1t +DM5I1rblJk4IUpXoWsQWS2YGS6cpsoifTwsktq6olk/YW6YV+eSHuYARCByhBBlO +E2tBAiWjaRrbmVSeAZKxQpyiW2ZgVVJBE2ar9QOjEKcYECJxBu+L87uTTfITunW8 +bSPg4Um1AgMBAAECggEAAZPWukre+eaESE41DIBF4Je7S5nLA1vgQEL4Xylpb4Kj +O+6Ybw4TzPMfoth92VOuHyQeqR7vC0AY48TptsrJT+02bZsPwy4DydTIwChW8ay4 +rZzKeUh7LQE4X1CG7aKo10Eo1N9hfkyQslsaRV1uhsGVZUI11GunmgPG8vVCm3j5 +bD4hQoXcuUY/d8VjnIeyZ0R79Y0Z+M5Zv/HP0YVkKMpLGaIJm8p0O5whkx8ztqOD ++9XVITYuiiQb17I7ab/14ZFrVeNTz9ubo5KYWwznLeUaux5Gi4wLMSK4Pr8Bpdwz +bGz2oL226iv/Nlz0rFsc/ftro4nvMDnlptRpM7paAQKBgQDft0HwEb9g13sIy4uI ++Ie1eniodvU/vghMJRorakLzQFtT8U7Jh7bA89zNvtUDvwl/QHNpVqnZTBPEv1j1 +Xz+n7HxDGp2eLkylvLIaqIs2Z5ZD8hRRR/d0ltx1SirFNILTEGnFF3IQ4pszUlUE +RcYUICnQJMaahlkFYH/PtHBcNQKBgQC79mLNrRtbWkkWbf+0rlJh7+g5O5m/vZW1 +f3E6SLtELhXxQMV4K+bzkjfF5Lee2DksxtAtIoZOB+OY7LoqVdqE3zRpFyxioiJN +bIQUTHZaXnGJn32qfuFjLOab42+Dc8t3iFw/g51dCaA/UdLwFLnCpxX4i5ShmCpA +9p/KuLPngQKBgD1Bt6tdoLKKriS9X0q1CqvVih5O3F6E0U7QRfcnVIe40okMpQ8n +uxHgdFBd9YPeFmKiqjdoxH88hpkz787YMtzvMyNIsWnzsYccQQRtrBjMime2bHvJ +IefpuxneohF3jG7wqpWOEuyur+KAo8jUtiUinXBh8YO0T8HaJ4UfGjkVAoGAM87l +zOs57yQjoRsQsCycaIJH7/6NklwfN7e47ee+Njy9r5G63DS9o8VZuiIgupe+qqji +GI67liZ2hWA6sBCZ+qXLPGw2v7kQ22ZdwXqR5LbDdLuRV71BQqTNq4o04na4Tmo3 +gwo0BcDxeoKDMcmEqjKDy84tWZ0niGByCt5+OAECgYAKlMHNGVSyiSezrlXEVpxv +BSM/f96hJFads4jeb4wUnKWZxJvywabJxG6ln3RgrderapY7oYTxsGTYERqUvZNm +MkqVYbLY9Shj+faE1Xw4xP78aRGhrTsqPyORtGBeIJl6zsb1s8+7u47BkSDBumph +tCLmQPQFmTQQUDP6g2FtHw== +-----END PRIVATE KEY----- _end_of_pem_ end