Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
RsaEndpoint.cs
1using System;
2using System.IO;
4using System.Text;
6
8{
12 public class RsaEndpoint : E2eEndpoint
13 {
14 private RSA rsa;
15 private readonly byte[] modulus;
16 private readonly byte[] exponent;
17 private readonly int keySize;
18 private byte[] publicKey;
19 private string publicKeyBase64;
20 private string modulusBase64;
21 private string exponentBase64;
22
26 public RsaEndpoint()
27 : this(4096)
28 {
29 }
30
35 public RsaEndpoint(int KeySize)
36 : this(CreateRSA(KeySize))
37 {
38 }
39
45 public RsaEndpoint(int KeySize, IE2eSymmetricCipher SymmetricCipher)
46 : this(CreateRSA(KeySize), SymmetricCipher)
47 {
48 }
49
50 private static RSA CreateRSA(int KeySize)
51 {
52 RSA Result = RSA.Create();
53
54 if (Result.KeySize != KeySize)
55 Result.KeySize = KeySize;
56
57 return Result;
58 }
59
64 public RsaEndpoint(RSA Rsa)
65 : this(Rsa, new Aes256())
66 {
67 }
68
74 public RsaEndpoint(RSA Rsa, IE2eSymmetricCipher SymmetricCipher)
75 : base(SymmetricCipher)
76 {
77 this.rsa = Rsa;
78
79 RSAParameters P = this.rsa.ExportParameters(false);
80
81 this.keySize = this.rsa.KeySize;
82 this.modulus = P.Modulus;
83 this.exponent = P.Exponent;
84
85 this.Init();
86 }
87
94 public RsaEndpoint(int KeySize, byte[] Modulus, byte[] Exponent)
95 : this(KeySize, Modulus, Exponent, new Aes256())
96 {
97 }
98
106 public RsaEndpoint(int KeySize, byte[] Modulus, byte[] Exponent,
107 IE2eSymmetricCipher SymmetricCipher)
108 : base(SymmetricCipher)
109 {
110 this.rsa = CreateRSA(KeySize);
111
112 this.keySize = KeySize;
113 this.modulus = Modulus;
114 this.exponent = Exponent;
115
116 RSAParameters Param = new RSAParameters()
117 {
120 };
121
122 this.rsa.ImportParameters(Param);
123
124 this.Init();
125 }
126
127 private void Init()
128 {
129 this.modulusBase64 = Convert.ToBase64String(this.modulus);
130 this.exponentBase64 = Convert.ToBase64String(this.exponent);
131
132 int c = this.modulus.Length;
133 int d = this.exponent.Length;
134
135 this.publicKey = new byte[2 + c + d];
136
137 this.publicKey[0] = (byte)(this.keySize);
138 this.publicKey[1] = (byte)(this.keySize >> 8);
139 Buffer.BlockCopy(this.modulus, 0, this.publicKey, 2, c);
140 Buffer.BlockCopy(this.exponent, 0, this.publicKey, c + 2, d);
141
142 this.publicKeyBase64 = Convert.ToBase64String(this.publicKey);
143 }
144
148 public override string LocalName => "rsa";
149
153 public int KeySize => this.keySize;
154
158 public override byte[] PublicKey => this.publicKey;
159
163 public override string PublicKeyBase64 => this.publicKeyBase64;
164
168 public byte[] Modulus => this.modulus;
169
173 public byte[] Exponent => this.exponent;
174
178 public override int SecurityStrength
179 {
180 get
181 {
182 if (this.keySize < 768)
183 return 0;
184 else if (this.keySize < 1024)
185 return 80;
186 else if (this.keySize < 2048)
187 return 96;
188 else if (this.keySize < 3072)
189 return 112;
190 else if (this.keySize < 4096)
191 return 128;
192 else if (this.keySize < 7680)
193 return 140;
194 else if (this.keySize < 15360)
195 return 192;
196 else
197 return 256;
198 }
199 }
200
207 {
208 int KeySize;
209
210 if (SecurityStrength <= 80)
211 KeySize = 768;
212 else if (SecurityStrength <= 96)
213 KeySize = 1024;
214 else if (SecurityStrength <= 112)
215 KeySize = 2048;
216 else if (SecurityStrength <= 128)
217 KeySize = 3072;
218 else if (SecurityStrength <= 140)
219 KeySize = 4096;
220 else if (SecurityStrength <= 192)
221 KeySize = 7680;
222 else if (SecurityStrength <= 256)
223 KeySize = 15360;
224 else
225 throw new ArgumentException("Key strength too high.", nameof(SecurityStrength));
226
227 RSA Rsa = CreateRSA(KeySize);
228
229 return new RsaEndpoint(Rsa, this.DefaultSymmetricCipher.CreteNew());
230 }
231
237 public override IE2eEndpoint CreatePrivate(byte[] Secret)
238 {
239 RSAParameters P = new RSAParameters();
240 string s = Encoding.ASCII.GetString(Secret);
241 string[] Parts = s.Split(',');
242 string Name;
243 byte[] Value;
244 int i;
245
246 foreach (string Part in Parts)
247 {
248 i = Part.IndexOf('=');
249 if (i < 0)
250 continue;
251
252 Name = Part[..i];
253 Value = Convert.FromBase64String(Part[(i + 1)..]);
254
255 switch (Name)
256 {
257 case "D": P.D = Value; break;
258 case "DP": P.DP = Value; break;
259 case "DQ": P.DQ = Value; break;
260 case "Exponent": P.Exponent = Value; break;
261 case "InverseQ": P.InverseQ = Value; break;
262 case "Modulus": P.Modulus = Value; break;
263 case "P": P.P = Value; break;
264 case "Q": P.Q = Value; break;
265 }
266 }
267
268 RSA Rsa = RSA.Create();
269 Rsa.ImportParameters(P);
270
271 return new RsaEndpoint(Rsa, this.DefaultSymmetricCipher.CreteNew());
272 }
273
279 public byte[] Export(bool Private)
280 {
281 RSAParameters P = this.rsa.ExportParameters(Private);
282 StringBuilder sb = new StringBuilder();
283
284 sb.Append("Exponent=");
285 sb.Append(Convert.ToBase64String(P.Exponent));
286 sb.Append(",Modulus=");
287 sb.Append(Convert.ToBase64String(P.Modulus));
288 if (Private)
289 {
290 sb.Append(",D=");
291 sb.Append(Convert.ToBase64String(P.D));
292 sb.Append(",DP=");
293 sb.Append(Convert.ToBase64String(P.DP));
294 sb.Append(",DQ=");
295 sb.Append(Convert.ToBase64String(P.DQ));
296 sb.Append(",InverseQ=");
297 sb.Append(Convert.ToBase64String(P.InverseQ));
298 sb.Append(",P=");
299 sb.Append(Convert.ToBase64String(P.P));
300 sb.Append(",Q=");
301 sb.Append(Convert.ToBase64String(P.P));
302 }
303
304 return Encoding.ASCII.GetBytes(sb.ToString());
305 }
306
312 public override IE2eEndpoint CreatePublic(byte[] PublicKey)
313 {
314 if (PublicKey.Length < 2)
315 throw new ArgumentException("Invalid public key.", nameof(PublicKey));
316
317 int KeySize = PublicKey[1];
318 KeySize <<= 8;
319 KeySize |= PublicKey[0];
320
321 int ModSize = KeySize >> 3;
322 if (PublicKey.Length < 2 + ModSize)
323 throw new ArgumentException("Invalid public key.", nameof(PublicKey));
324
325 int ExpSize = PublicKey.Length - 2 - ModSize;
326 if (ExpSize <= 0)
327 throw new ArgumentException("Invalid public key.", nameof(PublicKey));
328
329 byte[] Modulus = new byte[ModSize];
330 byte[] Exponent = new byte[ExpSize];
331
332 Buffer.BlockCopy(PublicKey, 2, Modulus, 0, ModSize);
333 Buffer.BlockCopy(PublicKey, 2 + ModSize, Exponent, 0, ExpSize);
334
336 }
337
339 public override void Dispose()
340 {
341 base.Dispose();
342
343 this.rsa?.Dispose();
344 this.rsa = null;
345 }
346
355 public override byte[] GetSharedSecretForEncryption(IE2eEndpoint RemoteEndpoint,
356 IE2eSymmetricCipher Cipher, out byte[] CipherText)
357 {
358 if (!(RemoteEndpoint is RsaEndpoint RemoteRsaEndpoint))
359 throw new InvalidOperationException("Remote endpoint is not an RSA endpoint.");
360
361 byte[] Secret = Cipher.GenerateKey();
362
363 lock (RemoteRsaEndpoint.rsa)
364 {
365 CipherText = RemoteRsaEndpoint.rsa.Encrypt(Secret, RSAEncryptionPadding.OaepSHA256);
366 }
367
368 return Secret;
369 }
370
378 public override byte[] GetSharedSecretForDecryption(IE2eEndpoint RemoteEndpoint,
379 byte[] CipherText)
380 {
381 lock (this.rsa)
382 {
383 return this.rsa.Decrypt(CipherText, RSAEncryptionPadding.OaepSHA256);
384 }
385 }
386
390 public override bool SharedSecretUseCipherText => true;
391
397 public override byte[] Sign(byte[] Data)
398 {
399 return this.rsa.SignData(Data, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
400 }
401
407 public override byte[] Sign(Stream Data)
408 {
409 return this.rsa.SignData(Data, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
410 }
411
418 public override bool Verify(byte[] Data, byte[] Signature)
419 {
420 return RsaEndpoint.Verify(Data, Signature, this.keySize, this.modulus, this.exponent);
421 }
422
429 public override bool Verify(Stream Data, byte[] Signature)
430 {
431 return RsaEndpoint.Verify(Data, Signature, this.keySize, this.modulus, this.exponent);
432 }
433
442 public static bool Verify(byte[] Data, byte[] Signature, int KeySize, byte[] PublicKey)
443 {
444 int c = KeySize >> 3;
445 int d = PublicKey.Length - c;
446 if (d <= 0)
447 throw new ArgumentException("Invalid public key.", nameof(PublicKey));
448
449 byte[] Modulus = new byte[c];
450 byte[] Exponent = new byte[d];
451
452 Buffer.BlockCopy(PublicKey, 0, Modulus, 0, c);
453 Buffer.BlockCopy(PublicKey, c, Exponent, 0, d);
454
455 return Verify(Data, Signature, KeySize, Modulus, Exponent);
456 }
457
466 public static bool Verify(Stream Data, byte[] Signature, int KeySize, byte[] PublicKey)
467 {
468 int c = KeySize >> 3;
469 int d = PublicKey.Length - c;
470 if (d <= 0)
471 throw new ArgumentException("Invalid public key.", nameof(PublicKey));
472
473 byte[] Modulus = new byte[c];
474 byte[] Exponent = new byte[d];
475
476 Buffer.BlockCopy(PublicKey, 0, Modulus, 0, c);
477 Buffer.BlockCopy(PublicKey, c, Exponent, 0, d);
478
479 return Verify(Data, Signature, KeySize, Modulus, Exponent);
480 }
481
491 public static bool Verify(byte[] Data, byte[] Signature, int KeySize, byte[] Modulus, byte[] Exponent)
492 {
493 using RSA Rsa = CreateRSA(KeySize);
494 RSAParameters P = new RSAParameters()
495 {
498 };
499
500 Rsa.ImportParameters(P);
501
502 return Rsa.VerifyData(Data, Signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
503 }
504
514 public static bool Verify(Stream Data, byte[] Signature, int KeySize, byte[] Modulus, byte[] Exponent)
515 {
516 using RSA Rsa = CreateRSA(KeySize);
517 RSAParameters P = new RSAParameters()
518 {
521 };
522
523 Rsa.ImportParameters(P);
524
525 return Rsa.VerifyData(Data, Signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
526 }
527
531 public override bool Slow => true;
532
534 public override bool Equals(object obj)
535 {
536 return obj is RsaEndpoint RsaEndpoint &&
537 this.keySize.Equals(RsaEndpoint.keySize) &&
538 this.modulusBase64.Equals(RsaEndpoint.modulusBase64) &&
539 this.exponentBase64.Equals(RsaEndpoint.exponentBase64);
540 }
541
543 public override int GetHashCode()
544 {
545 int Result = this.keySize.GetHashCode();
546 Result ^= Result << 5 ^ this.modulusBase64.GetHashCode();
547 Result ^= Result << 5 ^ this.exponentBase64.GetHashCode();
548
549 return Result;
550 }
551 }
552}
Abstract base class for End-to-End encryption schemes.
Definition: E2eEndpoint.cs:14
virtual IE2eSymmetricCipher DefaultSymmetricCipher
Default symmetric cipher.
Definition: E2eEndpoint.cs:282
RSA / AES-256 hybrid cipher.
Definition: RsaEndpoint.cs:13
override byte[] Sign(Stream Data)
Signs binary data using the local private key.
Definition: RsaEndpoint.cs:407
RsaEndpoint(int KeySize, byte[] Modulus, byte[] Exponent)
RSA / AES-256 hybrid cipher.
Definition: RsaEndpoint.cs:94
override int SecurityStrength
Security strength of End-to-End encryption scheme.
Definition: RsaEndpoint.cs:179
byte[] Modulus
Modulus of RSA public key.
Definition: RsaEndpoint.cs:168
override string PublicKeyBase64
Remote public key, as a Base64 string.
Definition: RsaEndpoint.cs:163
override IE2eEndpoint CreatePublic(byte[] PublicKey)
Creates a new endpoint given a public key.
Definition: RsaEndpoint.cs:312
override void Dispose()
IDisposable.Dispose
Definition: RsaEndpoint.cs:339
override bool Verify(Stream Data, byte[] Signature)
Verifies a signature.
Definition: RsaEndpoint.cs:429
override byte[] GetSharedSecretForEncryption(IE2eEndpoint RemoteEndpoint, IE2eSymmetricCipher Cipher, out byte[] CipherText)
Gets a shared secret for encryption, and optionally a corresponding cipher text.
Definition: RsaEndpoint.cs:355
RsaEndpoint()
RSA / AES-256 hybrid cipher.
Definition: RsaEndpoint.cs:26
byte[] Export(bool Private)
Exports information from the encryption object.
Definition: RsaEndpoint.cs:279
RsaEndpoint(int KeySize)
RSA / AES-256 hybrid cipher.
Definition: RsaEndpoint.cs:35
override bool Slow
If implementation is slow, compared to other options.
Definition: RsaEndpoint.cs:531
override bool Verify(byte[] Data, byte[] Signature)
Verifies a signature.
Definition: RsaEndpoint.cs:418
override IE2eEndpoint Create(int SecurityStrength)
Creates a new key.
Definition: RsaEndpoint.cs:206
static bool Verify(byte[] Data, byte[] Signature, int KeySize, byte[] Modulus, byte[] Exponent)
Verifies a signature.
Definition: RsaEndpoint.cs:491
override bool SharedSecretUseCipherText
If the recipient needs a cipher text to generate the same shared secret.
Definition: RsaEndpoint.cs:390
override byte[] Sign(byte[] Data)
Signs binary data using the local private key.
Definition: RsaEndpoint.cs:397
byte[] Exponent
Exponent of RSA public key.
Definition: RsaEndpoint.cs:173
override string LocalName
Local name of the E2E encryption scheme
Definition: RsaEndpoint.cs:148
static bool Verify(byte[] Data, byte[] Signature, int KeySize, byte[] PublicKey)
Verifies a signature.
Definition: RsaEndpoint.cs:442
RsaEndpoint(int KeySize, IE2eSymmetricCipher SymmetricCipher)
RSA / AES-256 hybrid cipher.
Definition: RsaEndpoint.cs:45
override bool Equals(object obj)
Definition: RsaEndpoint.cs:534
RsaEndpoint(int KeySize, byte[] Modulus, byte[] Exponent, IE2eSymmetricCipher SymmetricCipher)
RSA / AES-256 hybrid cipher.
Definition: RsaEndpoint.cs:106
static bool Verify(Stream Data, byte[] Signature, int KeySize, byte[] PublicKey)
Verifies a signature.
Definition: RsaEndpoint.cs:466
RsaEndpoint(RSA Rsa, IE2eSymmetricCipher SymmetricCipher)
RSA / AES-256 hybrid cipher.
Definition: RsaEndpoint.cs:74
override IE2eEndpoint CreatePrivate(byte[] Secret)
Creates a new endpoint given a private key.
Definition: RsaEndpoint.cs:237
static bool Verify(Stream Data, byte[] Signature, int KeySize, byte[] Modulus, byte[] Exponent)
Verifies a signature.
Definition: RsaEndpoint.cs:514
override byte[] GetSharedSecretForDecryption(IE2eEndpoint RemoteEndpoint, byte[] CipherText)
Gets a shared secret for decryption.
Definition: RsaEndpoint.cs:378
RsaEndpoint(RSA Rsa)
RSA / AES-256 hybrid cipher.
Definition: RsaEndpoint.cs:64
override byte[] PublicKey
Remote public key.
Definition: RsaEndpoint.cs:158
Implements support for the AES-256 cipher in hybrid End-to-End encryption schemes.
Definition: Aes256.cs:17
Abstract base class for End-to-End encryption schemes.
Definition: IE2eEndpoint.cs:13
Interface for symmetric ciphers.
byte[] GenerateKey()
Generates a new key. Used when the asymmetric cipher cannot calculate a shared secret.
IE2eSymmetricCipher CreteNew()
Creates a new symmetric cipher object with the same settings as the current object.