Skip to content

Commit 6cfee5c

Browse files
TimHessbart-vmware
authored andcommitted
Fix unexpected OAEP algorithm downgrade
- add integration test with Config Server - move non-hex salt theory data to AesTextDecryptorTest - add docker-compose for integration tests to repo root
1 parent 8dd97cc commit 6cfee5c

8 files changed

Lines changed: 115 additions & 23 deletions

File tree

.github/workflows/Steeltoe.All.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ jobs:
5454
eureka.client.serviceUrl.defaultZone: http://eurekaServer:8761/eureka
5555
eureka.instance.hostname: localhost
5656
eureka.instance.instanceId: localhost:configServer:8888
57+
encrypt.keyStore.location: file:///workspace/server.jks
58+
encrypt.keyStore.password: letmein
59+
encrypt.keyStore.alias: mytestkey
60+
encrypt.rsa.algorithm: OAEP
61+
encrypt.rsa.salt: deadbeef
62+
encrypt.rsa.strong: "false"
63+
options: --name steeltoe-config
5764
ports:
5865
- 8888:8888
5966

@@ -83,6 +90,15 @@ jobs:
8390
with:
8491
persist-credentials: false
8592

93+
- name: Provide jks file for Config Server container
94+
if: ${{ matrix.runDockerContainers }}
95+
# The Config Server container starts before checkout, when server.jks is not yet available.
96+
# Copy it into the container now and restart so Config Server can pick up the keystore.
97+
shell: bash
98+
run: |
99+
docker cp src/Configuration/test/Encryption.Test/Cryptography/server.jks steeltoe-config:/workspace/server.jks
100+
docker restart steeltoe-config
101+
86102
- name: Restore packages
87103
run: dotnet restore ${{ env.SOLUTION_FILE }} /p:Configuration=Release /p:NuGetAudit=false --verbosity minimal
88104

.github/workflows/component-shared-workflow.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ jobs:
4545
eureka.client.serviceUrl.defaultZone: http://eurekaServer:8761/eureka
4646
eureka.instance.hostname: localhost
4747
eureka.instance.instanceId: localhost:configServer:8888
48+
encrypt.keyStore.location: file:///workspace/server.jks
49+
encrypt.keyStore.password: letmein
50+
encrypt.keyStore.alias: mytestkey
51+
encrypt.rsa.algorithm: OAEP
52+
encrypt.rsa.salt: deadbeef
53+
encrypt.rsa.strong: "false"
54+
options: --name steeltoe-config
4855
ports:
4956
- 8888:8888
5057

@@ -74,6 +81,15 @@ jobs:
7481
with:
7582
persist-credentials: false
7683

84+
- name: Provide jks file for Config Server container
85+
if: ${{ inputs.runDockerContainers }}
86+
# The Config Server container starts before checkout, when server.jks is not yet available.
87+
# Copy it into the container now and restart so Config Server can pick up the keystore.
88+
shell: bash
89+
run: |
90+
docker cp src/Configuration/test/Encryption.Test/Cryptography/server.jks steeltoe-config:/workspace/server.jks
91+
docker restart steeltoe-config
92+
7793
- name: Restore packages
7894
run: dotnet restore ${{ env.SOLUTION_FILE }} /p:Configuration=Release /p:NuGetAudit=false --verbosity minimal
7995

docker-compose.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Starts Eureka Server and Spring Cloud Config Server for running Configuration integration tests locally.
2+
#
3+
# Usage:
4+
# docker compose up -d
5+
# Start-Sleep -Seconds 15 # wait for servers to be ready
6+
#
7+
# Run all Configuration integration tests:
8+
# dotnet test src/Configuration --filter "Category=Integration"
9+
#
10+
# To generate a new OAEP-encrypted test vector (for Encryption.Test):
11+
# Invoke-RestMethod -Method Post -Uri "http://localhost:8888/encrypt" `
12+
# -Body "encrypt the world" -ContentType "text/plain"
13+
14+
services:
15+
eureka-server:
16+
image: steeltoe.azurecr.io/eureka-server
17+
pull_policy: always
18+
container_name: eureka-server
19+
ports:
20+
- "8761:8761"
21+
22+
config-server:
23+
image: steeltoe.azurecr.io/config-server
24+
pull_policy: always
25+
container_name: steeltoe-config
26+
depends_on:
27+
- eureka-server
28+
ports:
29+
- "8888:8888"
30+
volumes:
31+
- ./src/Configuration/test/Encryption.Test/Cryptography/server.jks:/workspace/server.jks:ro
32+
environment:
33+
eureka.client.enabled: "true"
34+
eureka.client.serviceUrl.defaultZone: http://eureka-server:8761/eureka
35+
eureka.instance.hostname: localhost
36+
eureka.instance.instanceId: localhost:configServer:8888
37+
encrypt.keyStore.location: file:///workspace/server.jks
38+
encrypt.keyStore.password: letmein
39+
encrypt.keyStore.alias: mytestkey
40+
encrypt.rsa.algorithm: OAEP
41+
encrypt.rsa.salt: deadbeef
42+
encrypt.rsa.strong: "false"

src/Configuration/src/Encryption/Cryptography/RsaKeyStoreDecryptor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ private IBufferedCipher CreateCipher(string algorithm)
4040
return algorithm.ToUpperInvariant() switch
4141
{
4242
"DEFAULT" => CipherUtilities.GetCipher("RSA/NONE/PKCS1Padding"),
43-
"OAEP" => CipherUtilities.GetCipher("RSA/ECB/PKCS1"),
43+
"OAEP" => CipherUtilities.GetCipher("RSA/NONE/OAEPWithSHA1AndMGF1Padding"),
4444
_ => throw new ArgumentException("algorithm should be one of DEFAULT or OAEP")
4545
};
4646
}

src/Configuration/test/ConfigServer.Integration.Test/ConfigServerConfigurationExtensionsIntegrationTest.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,11 @@
99

1010
namespace Steeltoe.Configuration.ConfigServer.Integration.Test;
1111

12-
// NOTE: Some of the tests assume a running Spring Cloud Config Server is started
12+
// NOTE: These tests assume Spring Cloud Config Server (and sometimes Eureka Server) is running
1313
// with repository data for application: foo, profile: development
1414
//
15-
// The easiest way to get that to happen is clone the spring-cloud-config
16-
// repo and run the config-server.
17-
// e.g. git clone https://github.com/spring-cloud/spring-cloud-config.git
18-
// cd spring-cloud-config\spring-cloud-config-server
19-
// mvn spring-boot:run
15+
// The easiest way to run the servers is with docker compose
16+
// (see docker-compose.yml at the repo root)
2017
public sealed class ConfigServerConfigurationExtensionsIntegrationTest
2118
{
2219
[Fact]

src/Configuration/test/ConfigServer.Integration.Test/PlaceholderEncryptionIntegrationTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public void PlaceholderInsideDecryptionProvider_ReturnsDecryptedValuesInPlacehol
2626
["encrypt:rsa:algorithm"] = "OAEP",
2727
["encrypt:rsa:salt"] = "deadbeef",
2828
["encrypted"] =
29-
"{cipher}AQATBPXCmri0MCEoCam0noXJgKGlFfE/chVN7XhH1V23MqJ8sI3lI61PyvsryJP3LlfNn38gUuulMeslAs/gUCoPFPV/zD7M8x527wQUbmWD6bR0ZMJ4hu3DisK6Diw2YAOxXSsm3Zh46cPFQcowfOG1x2OXj+5uL4T+VBGdt3Nr6dHCOumkTJ1KAtaJMfASf3J8G4M27v6m4Y2EdBqP1zWwDhAZ3R0u9uTP9xYUqQiKsUeOixrhOaCvtb1Q+Zg6A41CxM4cjL3Ty6miNYLx3QkxRvfkdo0iqo7jTrWWAT1aeRV6t5U5iMlWnD4eXzad60E3ZSINhvDiB03xPPPuHKC6qUTRJEEbQFegmn/KIPMMn9WaH/JLLZNvQYMuaFszZ84AE3aQcH0be+sNFDSjHNHL",
29+
"{cipher}AQBoKgZNlxY+EWcGG0CXhyfV4q/u7lJjCBS+9liSKpu/w4gNmJhTYvjDJ3XIExVSVit41po5n91LVI3h777QlY7b0D2zOI0f4YR/9MtAdsq/cgRGZ4uzcv69bmVnQ0yt5ilxV021TH0EsVEmwmgyY+n1mKcD7aXWQwS2lAvJycgVgrDfbj2qz2c7aPn+8mXvG8EAbNmEhCbATCdPDlmBUPjLvuSweDlzlefQJ+jVSxLHfOcQ+g17arhIH1j0nZEAGywoNBGS1xg6DQ+8sW0GiYennTrnKslzMFjPTQ8QJSONzYysdRLGbV2Bi73ifUd+4AnMuSKcIRNiRACRtt+i7ZhrgTWRV1F+F8vfIiqf3SfzHdyclHkoCVkPhNBc9ySq0XRubPtg7UnW2KPZufZ0D7xx",
3030
["placeholder"] = "${encrypted}"
3131
};
3232

@@ -59,7 +59,7 @@ public void DecryptionInsidePlaceholderProvider_ReturnsDecryptedValuesInPlacehol
5959
["encrypt:rsa:algorithm"] = "OAEP",
6060
["encrypt:rsa:salt"] = "deadbeef",
6161
["encrypted"] =
62-
"{cipher}AQATBPXCmri0MCEoCam0noXJgKGlFfE/chVN7XhH1V23MqJ8sI3lI61PyvsryJP3LlfNn38gUuulMeslAs/gUCoPFPV/zD7M8x527wQUbmWD6bR0ZMJ4hu3DisK6Diw2YAOxXSsm3Zh46cPFQcowfOG1x2OXj+5uL4T+VBGdt3Nr6dHCOumkTJ1KAtaJMfASf3J8G4M27v6m4Y2EdBqP1zWwDhAZ3R0u9uTP9xYUqQiKsUeOixrhOaCvtb1Q+Zg6A41CxM4cjL3Ty6miNYLx3QkxRvfkdo0iqo7jTrWWAT1aeRV6t5U5iMlWnD4eXzad60E3ZSINhvDiB03xPPPuHKC6qUTRJEEbQFegmn/KIPMMn9WaH/JLLZNvQYMuaFszZ84AE3aQcH0be+sNFDSjHNHL",
62+
"{cipher}AQBoKgZNlxY+EWcGG0CXhyfV4q/u7lJjCBS+9liSKpu/w4gNmJhTYvjDJ3XIExVSVit41po5n91LVI3h777QlY7b0D2zOI0f4YR/9MtAdsq/cgRGZ4uzcv69bmVnQ0yt5ilxV021TH0EsVEmwmgyY+n1mKcD7aXWQwS2lAvJycgVgrDfbj2qz2c7aPn+8mXvG8EAbNmEhCbATCdPDlmBUPjLvuSweDlzlefQJ+jVSxLHfOcQ+g17arhIH1j0nZEAGywoNBGS1xg6DQ+8sW0GiYennTrnKslzMFjPTQ8QJSONzYysdRLGbV2Bi73ifUd+4AnMuSKcIRNiRACRtt+i7ZhrgTWRV1F+F8vfIiqf3SfzHdyclHkoCVkPhNBc9ySq0XRubPtg7UnW2KPZufZ0D7xx",
6363
["placeholder"] = "${encrypted}"
6464
};
6565

src/Configuration/test/Encryption.Test/Cryptography/AesTextDecryptorTest.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@ public static TheoryData<string, string, string, string> GetTestVector()
2323
List<(string Salt, string Key, string Cipher, string PlainText)> data =
2424
[
2525
("deadbeef", "12345678901234567890", "23f97efeed4ab62294432e8ef6b2905e336c245ecb1d5122b2c288c4deeae1b737952312e97e2cf013dd31a28fc60704",
26-
"encrypt the world"), // from Spring Cloud Config documentation
26+
"encrypt the world"),
2727
("deadbeef", "foo", "682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda", "mysecret"),
2828
("deadbeef", "12345678901234567890", "e31b13ab248f96f3cc22be5942d9ebec19a6b50318b2f5d30ea515064971bdebff6974890197626f0dcd5b648950e96f",
2929
"encrypt the world"),
3030
("deadbeef", "12345678901234567890", "e401ca0578839c9e5207f52d0ae4dc836f8c6530cdc90f14b544180f6fdb9265b80d6ace9fbbab700c7af32141171358",
31+
"encrypt the world"),
32+
("nohexsaltvalue", "12345678901234567890", "000102030405060708090a0b0c0d0e0f31fb8ea24a48e4ffed43352dfacfc9b89cd5ff630715fb4ffeb536c02111dd53",
3133
"encrypt the world")
3234
];
3335

src/Configuration/test/Encryption.Test/Cryptography/RsaKeyStoreDecryptorTest.cs

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information.
44

5+
using System.Text;
56
using Steeltoe.Configuration.Encryption.Cryptography;
67

78
namespace Steeltoe.Configuration.Encryption.Test.Cryptography;
@@ -42,8 +43,8 @@ public void Constructor_WithUnsupportedAlgorithmThrows()
4243
}
4344

4445
[Theory]
45-
[MemberData(nameof(GetTestVector))]
46-
public void Decode_TestForSpringConfigCipher_WithDefaultKey(string salt, string strong, string algorithm, string cipher, string plainText)
46+
[MemberData(nameof(GetSpringConfigServerTestVectors))]
47+
public void Decrypt_WithSpringCipherText_UsingDefaultKeyAlias(string salt, string strong, string algorithm, string cipher, string plainText)
4748
{
4849
var decryptor = new RsaKeyStoreDecryptor(_keyProvider, "mytestkey", salt, bool.Parse(strong), algorithm);
4950
string decrypted = decryptor.Decrypt(cipher);
@@ -52,33 +53,51 @@ public void Decode_TestForSpringConfigCipher_WithDefaultKey(string salt, string
5253
}
5354

5455
[Theory]
55-
[MemberData(nameof(GetTestVector))]
56-
public void Decode_TestForSpringConfigCipher_WithSpecifiedKey(string salt, string strong, string algorithm, string cipher, string plainText)
56+
[MemberData(nameof(GetSpringConfigServerTestVectors))]
57+
public void Decrypt_WithSpringCipherText_UsingExplicitKeyAlias(string salt, string strong, string algorithm, string cipher, string plainText)
5758
{
5859
var decryptor = new RsaKeyStoreDecryptor(_keyProvider, "someKey", salt, bool.Parse(strong), algorithm);
5960
string decrypted = decryptor.Decrypt(cipher, "mytestkey");
6061

6162
decrypted.Should().Be(plainText);
6263
}
6364

64-
public static TheoryData<string, string, string, string, string> GetTestVector()
65+
// Requires Config Server to be running with OAEP encryption configured (see docker-compose.yml at the repo root)
66+
[Fact]
67+
[Trait("Category", "Integration")]
68+
public async Task Decrypt_WithOaepAlgorithm_CanDecryptSpringConfigServerCipherText()
69+
{
70+
// ReSharper disable once ShortLivedHttpClient
71+
using var httpClient = new HttpClient();
72+
73+
HttpResponseMessage response = await httpClient.PostAsync(new Uri("http://localhost:8888/encrypt"),
74+
new StringContent("encrypt the world", Encoding.UTF8, "text/plain"), TestContext.Current.CancellationToken);
75+
76+
response.EnsureSuccessStatusCode();
77+
string springCipherText = await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken);
78+
79+
var decryptor = new RsaKeyStoreDecryptor(_keyProvider, "mytestkey", "deadbeef", false, "OAEP");
80+
string decrypted = decryptor.Decrypt(springCipherText);
81+
82+
decrypted.Should().Be("encrypt the world");
83+
}
84+
85+
// Pre-generated ciphertext is from Spring Cloud Config Server (steeltoe.azurecr.io/config-server:4.3.1)
86+
public static TheoryData<string, string, string, string, string> GetSpringConfigServerTestVectors()
6587
{
6688
List<(string Salt, string Strong, string Algorithm, string Cipher, string PlainText)> data =
6789
[
6890
("deadbeef", "false", "OAEP",
69-
"AQATBPXCmri0MCEoCam0noXJgKGlFfE/chVN7XhH1V23MqJ8sI3lI61PyvsryJP3LlfNn38gUuulMeslAs/gUCoPFPV/zD7M8x527wQUbmWD6bR0ZMJ4hu3DisK6Diw2YAOxXSsm3Zh46cPFQcowfOG1x2OXj+5uL4T+VBGdt3Nr6dHCOumkTJ1KAtaJMfASf3J8G4M27v6m4Y2EdBqP1zWwDhAZ3R0u9uTP9xYUqQiKsUeOixrhOaCvtb1Q+Zg6A41CxM4cjL3Ty6miNYLx3QkxRvfkdo0iqo7jTrWWAT1aeRV6t5U5iMlWnD4eXzad60E3ZSINhvDiB03xPPPuHKC6qUTRJEEbQFegmn/KIPMMn9WaH/JLLZNvQYMuaFszZ84AE3aQcH0be+sNFDSjHNHL",
70-
"encrypt the world"),
71-
("deadbeef", "false", "OAEP",
72-
"AQBoZM07gyw+GN0SXCkARLiSDjhN0flk07QP9+BsNnPEQD+alfH6A5FJwwuEf7d/kNJozppaZuHcPpDnRZbzmsRcqOcO0BiJFjsbX5K9o8jcAsGhDmLAf0jy/Ry1de6bELjZ4MPArbVN9numHTre4plXBXun2AVeNNBYG3yHed0A68o6FCc6UR/Pfdo/H+oTburn2qVKaZL+DAqIKHntcZjTLg/ZRa7MKUMCKiFEtV88U3lg+1YUqgz+XUmg2zyUsHgHNzYlTOtJWkFW51wNz/M2C92Zsu4R6bF1ewb2RM0N8VmjQAw6GpfLNX+CB3gGlDPsfGjc9qiF3zNsJSk88dm1+NruXeon5Nth691NQJ6DpgMXhhFzv7L/eyZKL/kZpGIVZK6dW3iePzsBtuFdrjiZ",
91+
"AQA5BZk2Pg7/nbcuTrJ/i4MDOIc831GfHLUg1GQlBtOvRJm2iXngfbPKcnTjbtZZ9X+qPnbdkUcTVbgYcsszY3uoqWIN5Yybwg+dHsqZTv1/XSvwR/kwflDg+I6C+dxg3GepoCAZSPi+J5/MsfCYJAp6KI3WW34tbqkqNlJq1TmF4b/AQHmP7Pth6cIsFE7svQ0xDQRhY61lJESLvLZ1Em4XpA4cfiye1YQhNud7/AKTtyENf7oPT/7siWBN82gyCB63/HEMRNtSLobOKO1XzgWNc96ms4pIhACOA3cZarTDUqaKY+B84ATV5QKgfkQ/ihI6r2oeYB24ApKwjNyE4F4b0bFH1cchdsbooreJlflgn0U9gK0oo8t7cVGnih3lccJs3t0uAFVm+SrJGMG/8rgp",
7392
"encrypt the world"),
7493
("beefdead", "true", "OAEP",
75-
"AQAbWqohCeQ+TTqyJ3ZlNvAtx5cC2I3PmJetuSR82yRRyX+wWd7mTkUXuN/wANJ+nr1ySdzPudjml1lHaxZn42I9szkIKSkNT+6Yg+zNaREMetcE5SXA1awtSbEaFY2NcualSzPVWs8ulsUkKlYyyh6XP9gT/kODbmX0mS6DCtxalJgjei7WujLaJaPjc3jk+EhV9M1TovexqI7XoLlsgrGf6/1gQE+SSOamTFJopWpYEeSpSEwY2dXZfct5KCFWGJVA7eDPRJk0dT6EWIvqd6J4YoMWonxgVy4nG/Gq0NTisXv9XpJHAPYBg0c8B0WrWi2PG/Q00wvFRqGmYQ1hQIVmbJm8z+f0WoCxKwnCZvvdLlgrx2qeK1S21dPdgtmLXlj5bRUrektFrNhlevlENW7wgg==",
94+
"AQAwoGhHV/Z82UWIrmqmTT92L510iKkwiF+EhlroV/No3dLwamUovEB9n/4IF+j6wfv8q1Baqekn5y6folcQmiMJd86JHW2n+WNeKUlbjf3Rk5uwgSTL2ST1JZ8w6sZ0PZVE2tqaQoc9mHRmjT7hqRm1lQVsHsic5tCxdTmhYVdGp5J6UGTRPQNfyJBR34w+LFjtgyaOrF//o8Z5ZF9XUx3MGaoe4HnURIYRq5HHcd4yVFINaBpW19ndgPV+nWRANxnmltLgPUbLWBJSvJ8czHOfZvZnTSJrWDBp1GIHN0OFkObJAIl7hmOdCh3vFPkxOL9gH4690VlMOCWYI8elsvuFsOdPG++FtJVSbuGgYC3AnuFo955yBfy8tgdegQ5Zzb2sOS2mwqsWr4mly4Pis+bgpw==",
95+
"encrypt the world"),
96+
("deadbeef", "false", "DEFAULT",
97+
"AQBSAVVzUP21aZXVAnuTMBDQ+/HGatD/+6H2YT/EbVofx5pWNJIjOlq1ioDpLHRB/JS86nI5oC9scEVBajc/gcWiYJAOtG4+g0Sw2ixzmi3jmho/CYxhtbxGFrkrTOC0r/0I6gcGgCo5ZrQCtaQDUMnHn+aFwo8baduKQ2N6qMyGHvfXIqqJFabnTkYDlLlqgNa3jpI3oKicaDTvPU3jFO42fJyVFWyAdQ8YS0RZdOXV+0xQdRnHrHHjhR8W7D7e0Jyx05RKq1ZEXvN7+x+YSE7ajrwy8riGuxR9a8smZAKkXC8T7KcZMRqtkd/9bpNS10bpw21KSxxp2GF52ekbu0xZYIIPdIj57me7HGubwNd1kXXgV+3L6sZ1IUAN0xnOOEUQD3z6hOWkrTEAmSbNRdYM",
7698
"encrypt the world"),
7799
("beefdead", "true", "DEFAULT",
78100
"AQAhwKArLZqxrc44G2sG6+EwWeqn9JytaIyBpf/Yz2UZ0bLZthR3HPtGgOoKY9AkWpBuRzrw3zQ20ZRkq6q7XU+Stp1kB4OXhrmgbwydNUtYJmuTlpGohtHH8wVoT2n0bd7NuL9rJ2OAbkPXg8K1kJMSgen7Hyg3b+LFZmaA8wCHXdmHuP63Rk4NhSec4Ul/gRRn5jftojmbxVVQ6xRGAeFTZi70oAZ+tzdyXZmukorRZsUtnlgj94aSmGdMCGkukanCiEHHrh130Nigxba4qZ2F2e5n46De7+7EVwnIWWYa2sQH+3BQ+cp5OCebWMiGPdylqZzyTagkwo2jHv/OzW0/ytIF1Qo3AblMQgympSL3/PMPggllopaf2al4o7w63vWczXdv6YzdLchQMrdXRdkLrw==",
79-
"encrypt the world"),
80-
("nohexsaltvalue", "true", "DEFAULT",
81-
"AQA+sdMQ94WuW7DMBX7ZJQeWaybtFWJqAeVv9kmHyVCwil3yobQPXMxuoF/FGpZgYQu+9JyK52jnuIXiARdyqqaDKxY7ECN/8GLVXdcQi5ooO+ewyOrL53fycyyB2iQtZphbdgmzU2qKQkXvFcWQkauHCCtni6IemITLX/y9O3I6Ss9LEK86lSAWKD1Tikf9ly78vJsCJ01ahQhEQVMbkpTixnnFRgqSL7XZo+2FGMvsyYKHp9pQwEnLkbehI8AFODQlFsTcQ9YYab5lGa4OoYw+5oS3fFH8XlIvVSTfxipI18iyphppz3EefvuGd8FwgSGCbfIeQ2R2zcYxykfWgCgSH5ckev2EqeLaiyaK3tXFanumQBeLiSg7Uii80jg9LLJ62jyrR16m0+8CGqaw6uzZkQ==",
82101
"encrypt the world")
83102
];
84103

0 commit comments

Comments
 (0)