4
4
using System . Text ;
5
5
6
6
using NUnit . Framework ;
7
-
7
+ using Org . BouncyCastle . Asn1 ;
8
+ using Org . BouncyCastle . Asn1 . Gnu ;
9
+ using Org . BouncyCastle . Asn1 . Misc ;
8
10
using Org . BouncyCastle . Asn1 . Sec ;
9
11
using Org . BouncyCastle . Crypto ;
10
12
using Org . BouncyCastle . Crypto . Parameters ;
11
13
using Org . BouncyCastle . Security ;
12
14
using Org . BouncyCastle . Utilities ;
13
15
using Org . BouncyCastle . Utilities . Encoders ;
16
+ using Org . BouncyCastle . Utilities . IO ;
14
17
using Org . BouncyCastle . Utilities . Test ;
15
18
16
19
namespace Org . BouncyCastle . Bcpg . OpenPgp . Tests
@@ -51,6 +54,40 @@ public class PgpECDHTest
51
54
"6HiuFH7VKWcxPUBjXwf5+Z3uOKEp28tBgNyDrdbr1BbqlgYzIKq/pe9zUbUXfitn" +
52
55
"vFc6HcGhvmRQreQ+Yw1x3x0HJeoPwg==" ) ;
53
56
57
+ private static readonly byte [ ] testX25519PubKey =
58
+ Base64 . Decode (
59
+ "mDMEX9XwXhYJKwYBBAHaRw8BAQdAR5ZghmMHL8wldNlOkmbaiAOdyF5V5bgZdKq7" +
60
+ "L+yb4A20HEVDREggPHRlc3QuZWNkaEBleGFtcGxlLmNvbT6IkAQTFggAOBYhBGoy" +
61
+ "UrxNv7c3S2JjGzewWiN8tfzXBQJf1fBeAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4B" +
62
+ "AheAAAoJEDewWiN8tfzX0ZMA/AhEvrIgu+29eMQeuHOwX1ZY/UssU5TdVROQzGTL" +
63
+ "n5cgAP9hIKtt/mZ112HiAHDuWk2JskdtsuopnrEccz4PSEkSDLg4BF/V8F4SCisG" +
64
+ "AQQBl1UBBQEBB0DLPhNt/6GHDbb7vZW/iMsbXTZpgJNQiT6QA/4EzgYQLwMBCAeI" +
65
+ "eAQYFggAIBYhBGoyUrxNv7c3S2JjGzewWiN8tfzXBQJf1fBeAhsMAAoJEDewWiN8" +
66
+ "tfzXU34BAKJJLDee+qJCmUI20sMy/YoKfWmMnH2RBBHmLV8FAJ7vAP0e2wGixEfs" +
67
+ "oPqe8fHmvjQGxSByOyQGn7yD+oq9nVzTAA==" ) ;
68
+
69
+ private static readonly byte [ ] testX25519PrivKey =
70
+ Base64 . Decode (
71
+ "lIYEX9XwXhYJKwYBBAHaRw8BAQdAR5ZghmMHL8wldNlOkmbaiAOdyF5V5bgZdKq7" +
72
+ "L+yb4A3+BwMCMscozrXr93fOFmtxu/BJjEJrwRl20Jrv9lryfM+SF4UHgVMmJUpJ" +
73
+ "1RuTbSnM2KaqHwOgmdrvf2FJnpg1vMafBk1CmopqkRzzrbJ6xQhiPrQcRUNESCA8" +
74
+ "dGVzdC5lY2RoQGV4YW1wbGUuY29tPoiQBBMWCAA4FiEEajJSvE2/tzdLYmMbN7Ba" +
75
+ "I3y1/NcFAl/V8F4CGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQN7BaI3y1" +
76
+ "/NfRkwD8CES+siC77b14xB64c7BfVlj9SyxTlN1VE5DMZMuflyAA/2Egq23+ZnXX" +
77
+ "YeIAcO5aTYmyR22y6imesRxzPg9ISRIMnIsEX9XwXhIKKwYBBAGXVQEFAQEHQMs+" +
78
+ "E23/oYcNtvu9lb+IyxtdNmmAk1CJPpAD/gTOBhAvAwEIB/4HAwJ7ShSBrUuUAM5r" +
79
+ "G4I/gJKo+eBmbNC4NM81eALAF1vcovZPsGsiZ8IgXT64XiC1bpeAoINn6vM4vVbi" +
80
+ "LqNKqu6ll3ZgQ4po6vCW9GkhuEMmiHgEGBYIACAWIQRqMlK8Tb+3N0tiYxs3sFoj" +
81
+ "fLX81wUCX9XwXgIbDAAKCRA3sFojfLX811N+AQCiSSw3nvqiQplCNtLDMv2KCn1p" +
82
+ "jJx9kQQR5i1fBQCe7wD9HtsBosRH7KD6nvHx5r40BsUgcjskBp+8g/qKvZ1c0wA=" ) ;
83
+
84
+ private static readonly byte [ ] testX25519Message =
85
+ Base64 . Decode (
86
+ "hF4DbDc2fNL0VcUSAQdAqdV0v1D4X9cuGrT7+oQBpMFnw1wdfAcxH9xdO00s2HUw" +
87
+ "qB+XkIRETH7yesynLOKajmYftMWZRyTnW2tJUc1w5NFPjPxcbvd2bYmqkY57uAFg" +
88
+ "0kcBKhFklH2LRbBNThtQr3jn2YEFbNnhiGfOpoHfCn0oFh5RbXDwm+P3Q3tksvpZ" +
89
+ "wEGe2VkxLLe7BWnv/sRINQ2YpuaYshe8hw==" ) ;
90
+
54
91
private void Generate ( )
55
92
{
56
93
SecureRandom random = SecureRandom . GetInstance ( "SHA1PRNG" ) ;
@@ -105,6 +142,71 @@ private void Generate()
105
142
PgpPrivateKey pgpPrivKey = secRing . GetSecretKey ( ) . ExtractPrivateKey ( passPhrase ) ;
106
143
}
107
144
145
+ private void Generate25519 ( )
146
+ {
147
+ SecureRandom random = SecureRandom . GetInstance ( "SHA1PRNG" ) ;
148
+
149
+ //
150
+ // Generate a master key
151
+ //
152
+ IAsymmetricCipherKeyPairGenerator keyGen = GeneratorUtilities . GetKeyPairGenerator ( "Ed25519" ) ;
153
+ keyGen . Init ( new ECKeyGenerationParameters ( GnuObjectIdentifiers . Ed25519 , random ) ) ;
154
+
155
+ AsymmetricCipherKeyPair kpSign = keyGen . GenerateKeyPair ( ) ;
156
+
157
+ PgpKeyPair ecdsaKeyPair = new PgpKeyPair ( PublicKeyAlgorithmTag . EdDsa , kpSign , DateTime . UtcNow ) ;
158
+
159
+ //
160
+ // Generate an encryption key
161
+ //
162
+ keyGen = GeneratorUtilities . GetKeyPairGenerator ( "X25519" ) ;
163
+ keyGen . Init ( new ECKeyGenerationParameters ( MiscObjectIdentifiers . Curve25519 , random ) ) ;
164
+
165
+ AsymmetricCipherKeyPair kpEnc = keyGen . GenerateKeyPair ( ) ;
166
+
167
+ PgpKeyPair ecdhKeyPair = new PgpKeyPair ( PublicKeyAlgorithmTag . ECDH , kpEnc , DateTime . UtcNow ) ;
168
+
169
+ //
170
+ // Generate a key ring
171
+ //
172
+ char [ ] passPhrase = "test" . ToCharArray ( ) ;
173
+ PgpKeyRingGenerator keyRingGen = new PgpKeyRingGenerator ( PgpSignature . PositiveCertification , ecdsaKeyPair ,
174
+ "[email protected] " , SymmetricKeyAlgorithmTag . Aes256 , passPhrase , true , null , null , random ) ;
175
+ keyRingGen . AddSubKey ( ecdhKeyPair ) ;
176
+
177
+ PgpPublicKeyRing pubRing = keyRingGen . GeneratePublicKeyRing ( ) ;
178
+
179
+ // TODO: add check of KdfParameters
180
+ DoBasicKeyRingCheck ( pubRing ) ;
181
+
182
+ PgpSecretKeyRing secRing = keyRingGen . GenerateSecretKeyRing ( ) ;
183
+
184
+ PgpPublicKeyRing pubRingEnc = new PgpPublicKeyRing ( pubRing . GetEncoded ( ) ) ;
185
+ if ( ! Arrays . AreEqual ( pubRing . GetEncoded ( ) , pubRingEnc . GetEncoded ( ) ) )
186
+ {
187
+ Fail ( "public key ring encoding failed" ) ;
188
+ }
189
+
190
+ PgpSecretKeyRing secRingEnc = new PgpSecretKeyRing ( secRing . GetEncoded ( ) ) ;
191
+ if ( ! Arrays . AreEqual ( secRing . GetEncoded ( ) , secRingEnc . GetEncoded ( ) ) )
192
+ {
193
+ Fail ( "secret key ring encoding failed" ) ;
194
+ }
195
+
196
+ // Extract back the ECDH key and verify the encoded values to ensure correct endianness
197
+ PgpSecretKey pgpSecretKey = secRing . GetSecretKey ( ecdhKeyPair . KeyId ) ;
198
+ PgpPrivateKey pgpPrivKey = pgpSecretKey . ExtractPrivateKey ( passPhrase ) ;
199
+
200
+ if ( ! Arrays . AreEqual ( ( ( X25519PrivateKeyParameters ) kpEnc . Private ) . GetEncoded ( ) , ( ( X25519PrivateKeyParameters ) pgpPrivKey . Key ) . GetEncoded ( ) ) )
201
+ {
202
+ Fail ( "private key round trip failed" ) ;
203
+ }
204
+ if ( ! Arrays . AreEqual ( ( ( X25519PublicKeyParameters ) kpEnc . Public ) . GetEncoded ( ) , ( ( X25519PublicKeyParameters ) pgpSecretKey . PublicKey . GetKey ( ) ) . GetEncoded ( ) ) )
205
+ {
206
+ Fail ( "private key round trip failed" ) ;
207
+ }
208
+ }
209
+
108
210
private void TestDecrypt ( PgpSecretKeyRing secretKeyRing )
109
211
{
110
212
PgpObjectFactory pgpF = new PgpObjectFactory ( testMessage ) ;
@@ -134,14 +236,14 @@ private void TestDecrypt(PgpSecretKeyRing secretKeyRing)
134
236
// }
135
237
}
136
238
137
- private void EncryptDecryptTest ( )
239
+ private void EncryptDecryptTest ( string algorithm , DerObjectIdentifier curve )
138
240
{
139
241
SecureRandom random = SecureRandom . GetInstance ( "SHA1PRNG" ) ;
140
242
141
243
byte [ ] text = Encoding . ASCII . GetBytes ( "hello world!" ) ;
142
244
143
- IAsymmetricCipherKeyPairGenerator keyGen = GeneratorUtilities . GetKeyPairGenerator ( "ECDH" ) ;
144
- keyGen . Init ( new ECKeyGenerationParameters ( SecObjectIdentifiers . SecP256r1 , random ) ) ;
245
+ IAsymmetricCipherKeyPairGenerator keyGen = GeneratorUtilities . GetKeyPairGenerator ( algorithm ) ;
246
+ keyGen . Init ( new ECKeyGenerationParameters ( curve , random ) ) ;
145
247
146
248
AsymmetricCipherKeyPair kpEnc = keyGen . GenerateKeyPair ( ) ;
147
249
@@ -197,6 +299,39 @@ private void EncryptDecryptTest()
197
299
}
198
300
}
199
301
302
+ private void GnuPGCrossCheck ( )
303
+ {
304
+ PgpSecretKeyRing secretKeyRing = new PgpSecretKeyRing ( testX25519PrivKey ) ;
305
+
306
+ PgpObjectFactory pgpF = new PgpObjectFactory ( testX25519Message ) ;
307
+
308
+ PgpEncryptedDataList encList = ( PgpEncryptedDataList ) pgpF . NextPgpObject ( ) ;
309
+
310
+ PgpPublicKeyEncryptedData encP = ( PgpPublicKeyEncryptedData ) encList [ 0 ] ;
311
+
312
+ PgpSecretKey secretKey = secretKeyRing . GetSecretKey ( 0x6c37367cd2f455c5 ) ;
313
+
314
+ PgpPrivateKey pgpPrivKey = secretKey . ExtractPrivateKey ( "test" . ToCharArray ( ) ) ;
315
+
316
+ Stream clear = encP . GetDataStream ( pgpPrivKey ) ;
317
+
318
+ pgpF = new PgpObjectFactory ( clear ) ;
319
+
320
+ PgpCompressedData c1 = ( PgpCompressedData ) pgpF . NextPgpObject ( ) ;
321
+
322
+ pgpF = new PgpObjectFactory ( c1 . GetDataStream ( ) ) ;
323
+
324
+ PgpLiteralData ld = ( PgpLiteralData ) pgpF . NextPgpObject ( ) ;
325
+
326
+ Stream inLd = ld . GetDataStream ( ) ;
327
+ byte [ ] bytes = Streams . ReadAll ( inLd ) ;
328
+
329
+ if ( ! Arrays . AreEqual ( bytes , Encoding . ASCII . GetBytes ( "hello world!" ) ) )
330
+ {
331
+ Fail ( "wrong plain text in decrypted packet" ) ;
332
+ }
333
+ }
334
+
200
335
public override void PerformTest ( )
201
336
{
202
337
//
@@ -213,9 +348,15 @@ public override void PerformTest()
213
348
214
349
TestDecrypt ( secretKeyRing ) ;
215
350
216
- EncryptDecryptTest ( ) ;
351
+ EncryptDecryptTest ( "ECDH" , SecObjectIdentifiers . SecP256r1 ) ;
352
+
353
+ EncryptDecryptTest ( "X25519" , MiscObjectIdentifiers . Curve25519 ) ;
354
+
355
+ GnuPGCrossCheck ( ) ;
217
356
218
357
Generate ( ) ;
358
+
359
+ Generate25519 ( ) ;
219
360
}
220
361
221
362
private void DoBasicKeyRingCheck ( PgpPublicKeyRing pubKeyRing )
0 commit comments