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