├── .gitignore
├── Deps
├── libsodium-32.dll
└── libsodium-64.dll
├── Natrium
├── RandomNumberGenerator32.cs
├── RandomNumberGenerator64.cs
├── IRandomNumberGenerator.cs
├── IAuthenticatedPublicKeyCryptoContext.cs
├── IMessageSigner.cs
├── Properties
│ └── AssemblyInfo.cs
├── SignerKeyPair.cs
├── PublicKeyCryptoKeyPair.cs
├── MessageSigner64.cs
├── MessageSigner32.cs
├── IAuthenticatedPublicKeyCrypto.cs
├── Natrium.csproj
├── PrimitiveCryptoConstructs.cs
├── PlatformInvoke64.cs
├── PlatformInvoke32.cs
├── AuthenticatedPublicKeyCrypto32.cs
└── AuthenticatedPublicKeyCrypto64.cs
├── Natrium.sln
├── TestApp
├── Properties
│ └── AssemblyInfo.cs
├── Program.cs
└── TestApp.csproj
├── README.md
└── LICENSE.md
/.gitignore:
--------------------------------------------------------------------------------
1 | obj/
2 | bin/
3 | *~
4 | *.suo
--------------------------------------------------------------------------------
/Deps/libsodium-32.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XenocodeRCE/natrium/master/Deps/libsodium-32.dll
--------------------------------------------------------------------------------
/Deps/libsodium-64.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/XenocodeRCE/natrium/master/Deps/libsodium-64.dll
--------------------------------------------------------------------------------
/Natrium/RandomNumberGenerator32.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Natrium
4 | {
5 | internal sealed class RandomNumberGenerator32 : IRandomNumberGenerator
6 | {
7 | public void GetRandomBytes(byte[] buffer)
8 | {
9 | PlatformInvoke32.randombytes_buf(buffer, new UIntPtr((uint)buffer.Length));
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Natrium/RandomNumberGenerator64.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Natrium
4 | {
5 | internal sealed class RandomNumberGenerator64 : IRandomNumberGenerator
6 | {
7 | public void GetRandomBytes(byte[] buffer)
8 | {
9 | PlatformInvoke64.randombytes_buf(buffer, new UIntPtr((uint)buffer.Length));
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Natrium/IRandomNumberGenerator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Natrium
7 | {
8 | ///
9 | /// Provides a cryptographically secure random number generator
10 | ///
11 | public interface IRandomNumberGenerator
12 | {
13 | ///
14 | /// Fills a buffer with cryptographically secure random bytes
15 | ///
16 | /// The buffer to fill
17 | void GetRandomBytes(byte[] buffer);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Natrium/IAuthenticatedPublicKeyCryptoContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 |
7 | namespace Natrium
8 | {
9 | public interface IAuthenticatedPublicKeyCryptoContext
10 | {
11 | ///
12 | /// Encrypts and authenticates a message
13 | ///
14 | /// The message to encrypt
15 | /// An unique nonce value
16 | /// The encrypted message
17 | byte[] Encrypt(byte[] message, byte[] nonce);
18 |
19 | ///
20 | /// Verifies and decrypts a message
21 | ///
22 | /// The encrypted message
23 | /// The nonce value used to encrypt the message
24 | /// The decrypted message
25 | /// Thrown if integrity of the decrypted data cannot be confirmed
26 | byte[] VerifyAndDecrypt(byte[] encryptedMessage, byte[] nonce);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Natrium/IMessageSigner.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Natrium
7 | {
8 | ///
9 | /// Provides methods to digitally sign and verify messages
10 | ///
11 | public interface IMessageSigner
12 | {
13 | ///
14 | /// Creates a new random key pair
15 | ///
16 | /// The generated key pair
17 | SignerKeyPair CreateRandomKeyPair();
18 |
19 | ///
20 | /// Signs a message using the specified key pair
21 | ///
22 | /// The message to sign
23 | /// The key pair to use
24 | /// The signed message
25 | byte[] SignMessage(byte[] message, SignerKeyPair key);
26 |
27 | ///
28 | /// Verifies a signed message and returns the original message on success
29 | ///
30 | /// A signed message
31 | /// The public key to use for verification
32 | /// The original message that was signed
33 | byte[] VerifySignedMessage(byte[] signedMessage, SignerPublicKey publicKey);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Natrium.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.21005.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Natrium", "Natrium\Natrium.csproj", "{F16C829B-C9C9-4968-92DA-711EB0BB1071}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApp", "TestApp\TestApp.csproj", "{2F1A30AE-A44D-4C9E-A693-1C29B97E4412}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {F16C829B-C9C9-4968-92DA-711EB0BB1071}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {F16C829B-C9C9-4968-92DA-711EB0BB1071}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {F16C829B-C9C9-4968-92DA-711EB0BB1071}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {F16C829B-C9C9-4968-92DA-711EB0BB1071}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {2F1A30AE-A44D-4C9E-A693-1C29B97E4412}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {2F1A30AE-A44D-4C9E-A693-1C29B97E4412}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {2F1A30AE-A44D-4C9E-A693-1C29B97E4412}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {2F1A30AE-A44D-4C9E-A693-1C29B97E4412}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/Natrium/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("NSodium")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("NSodium")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("b171a7fb-7bda-4b52-a8ed-b2e01f1714df")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/TestApp/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("TestApp")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("TestApp")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("acd2dca0-c549-4b02-b62a-fd8837a9d4ce")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Natrium
2 | =======
3 |
4 | Natrium is an easy-to-use .NET wrapper for [libsodium](https://github.com/jedisct1/libsodium). Libsodium itself is a new, highly secure cryptographic library based on algorithms used in [NaCl](http://nacl.cr.yp.to/).
5 |
6 | Natrium makes it possible to implement _secure_ cryptography into your .NET applications using carefully selected algorithms chosen by cryptographic experts. The following excerpt is from libsodium web page:
7 | ```
8 | The design choices, particularly in regard to the Curve25519 Diffie-Hellman function, emphasize security (whereas NIST curves emphasize "performance" at the cost of security), and "magic constants" in NaCl/Sodium have clear rationales.
9 |
10 | The same cannot be said of NIST curves, where the specific origins of certain constants are not described by the standards.
11 |
12 | And despite the emphasis on higher security, primitives are faster across-the-board than most implementations of the NIST standards.
13 | ```
14 |
15 | ## Usage
16 |
17 | In order to use Natrium, you must build the VS solution to get Natrium.dll. When the build is done, you can reference Natrium.dll from your .NET project and start using the classes it contains. Remember to copy the files 'libsodium-32.dll' and 'libsodium-64.dll' from the Deps directory into same directory with your .NET executable files to make them available for Natrium to load.
18 |
19 | ### License
20 |
21 | Natrium is licensed under MIT license. Check the included file LICENSE.md for more details on how the included third-party libraries are licensed.
--------------------------------------------------------------------------------
/Natrium/SignerKeyPair.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Natrium
4 | {
5 | ///
6 | /// Represents a key pair used for digital signatures
7 | ///
8 | public sealed class SignerKeyPair : IDisposable
9 | {
10 | private readonly byte[] _secretKeyBytes;
11 | private readonly SignerPublicKey _publicKey;
12 |
13 | public SignerKeyPair(byte[] secretKeyBytes, byte[] publicKey)
14 | {
15 | _secretKeyBytes = secretKeyBytes;
16 | _publicKey = new SignerPublicKey(publicKey);
17 | }
18 |
19 | public void Dispose()
20 | {
21 | if (_secretKeyBytes != null) Array.Clear(_secretKeyBytes, 0, _secretKeyBytes.Length);
22 | _publicKey.Dispose();
23 | }
24 |
25 | ///
26 | /// The secret key part of the keypair
27 | ///
28 | public byte[] SecretKeyBytes
29 | {
30 | get { return _secretKeyBytes; }
31 | }
32 |
33 | ///
34 | /// The public key part of the keypair
35 | ///
36 | public SignerPublicKey PublicKey
37 | {
38 | get { return _publicKey; }
39 | }
40 | }
41 |
42 | ///
43 | /// Represents a public key used for digital signatures
44 | ///
45 | public sealed class SignerPublicKey : IDisposable
46 | {
47 | private readonly byte[] _keyBytes;
48 |
49 | public SignerPublicKey(byte[] keyBytes)
50 | {
51 | _keyBytes = keyBytes;
52 | }
53 |
54 | ///
55 | /// Gets the public-key bytes
56 | ///
57 | public byte[] PlainBytes
58 | {
59 | get { return _keyBytes; }
60 | }
61 |
62 | public void Dispose()
63 | {
64 | if (_keyBytes != null) Array.Clear(_keyBytes, 0, _keyBytes.Length);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Natrium/PublicKeyCryptoKeyPair.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Natrium
4 | {
5 | ///
6 | /// Represents a key pair used for authenticated public-key encryption
7 | ///
8 | public sealed class PublicKeyCryptoKeyPair : IDisposable
9 | {
10 | private readonly byte[] _secretKeyBytes;
11 | private readonly PublicKeyCryptoPublicKey _publicKey;
12 |
13 | public PublicKeyCryptoKeyPair(byte[] secretKeyBytes, byte[] publicKey)
14 | {
15 | _secretKeyBytes = secretKeyBytes;
16 | _publicKey = new PublicKeyCryptoPublicKey(publicKey);
17 | }
18 |
19 | public void Dispose()
20 | {
21 | if (_secretKeyBytes != null) Array.Clear(_secretKeyBytes, 0, _secretKeyBytes.Length);
22 | _publicKey.Dispose();
23 | }
24 |
25 | ///
26 | /// The secret key part of the keypair
27 | ///
28 | public byte[] SecretKeyBytes
29 | {
30 | get { return _secretKeyBytes; }
31 | }
32 |
33 | ///
34 | /// The public key part of the keypair
35 | ///
36 | public PublicKeyCryptoPublicKey PublicKey
37 | {
38 | get { return _publicKey; }
39 | }
40 | }
41 |
42 | ///
43 | /// Represents a public key used for authenticated public-key encryption
44 | ///
45 | public sealed class PublicKeyCryptoPublicKey : IDisposable
46 | {
47 | private readonly byte[] _keyBytes;
48 |
49 | public PublicKeyCryptoPublicKey(byte[] keyBytes)
50 | {
51 | _keyBytes = keyBytes;
52 | }
53 |
54 | ///
55 | /// Gets the public-key bytes
56 | ///
57 | public byte[] PlainBytes
58 | {
59 | get { return _keyBytes; }
60 | }
61 |
62 | public void Dispose()
63 | {
64 | if (_keyBytes != null) Array.Clear(_keyBytes, 0, _keyBytes.Length);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | natrium
2 | =======
3 |
4 | The MIT License (MIT)
5 |
6 | Copyright (c) 2014 Dextrey
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 |
27 |
28 |
29 |
30 | libsodium (https://github.com/jedisct1/libsodium/)
31 | ==================================================
32 |
33 | ```
34 | /*
35 | * Copyright (c) 2013-2014
36 | * Frank Denis
37 | *
38 | * Permission to use, copy, modify, and distribute this software for any
39 | * purpose with or without fee is hereby granted, provided that the above
40 | * copyright notice and this permission notice appear in all copies.
41 | *
42 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
43 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
44 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
45 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
47 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
48 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49 | */
50 | ```
51 |
52 |
--------------------------------------------------------------------------------
/Natrium/MessageSigner64.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 |
6 | namespace Natrium
7 | {
8 | internal sealed class MessageSigner64 : IMessageSigner
9 | {
10 | private readonly uint _publicKeyBytes;
11 | private readonly uint _secretKeyBytes;
12 | private readonly uint _bytes;
13 |
14 | public MessageSigner64()
15 | {
16 | _publicKeyBytes = PlatformInvoke64.crypto_sign_publickeybytes().ToUInt32();
17 | _secretKeyBytes = PlatformInvoke64.crypto_sign_secretkeybytes().ToUInt32();
18 | _bytes = PlatformInvoke64.crypto_sign_bytes().ToUInt32();
19 | }
20 |
21 | public SignerKeyPair CreateRandomKeyPair()
22 | {
23 | var publicKey = new byte[_publicKeyBytes];
24 | var secretKey = new byte[_secretKeyBytes];
25 | var result = PlatformInvoke64.crypto_sign_keypair(publicKey, secretKey);
26 |
27 | if (result != 0) throw new CryptographicException("Failed");
28 |
29 | return new SignerKeyPair(secretKey, publicKey);
30 | }
31 |
32 | public byte[] SignMessage(byte[] message, SignerKeyPair key)
33 | {
34 | var signedMessage = new byte[message.Length + _bytes];
35 | long signedMessageRealLength = 0;
36 |
37 | var result = PlatformInvoke64.crypto_sign(signedMessage, ref signedMessageRealLength, message, message.Length,
38 | key.SecretKeyBytes);
39 |
40 | if (result != 0) throw new CryptographicException("Failed");
41 |
42 | Array.Resize(ref signedMessage, (int)signedMessageRealLength);
43 | return signedMessage;
44 | }
45 |
46 | public byte[] VerifySignedMessage(byte[] signedMessage, SignerPublicKey publicKey)
47 | {
48 | var message = new byte[signedMessage.Length];
49 | long messageRealLength = 0;
50 |
51 | var result = PlatformInvoke64.crypto_sign_open(message, ref messageRealLength, signedMessage, signedMessage.Length,
52 | publicKey.PlainBytes);
53 |
54 | if (result != 0) throw new CryptographicException("Failed");
55 |
56 | Array.Resize(ref message, (int)messageRealLength);
57 | return message;
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Natrium/MessageSigner32.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 |
7 | namespace Natrium
8 | {
9 | internal sealed class MessageSigner32 : IMessageSigner
10 | {
11 | private readonly uint _publicKeyBytes;
12 | private readonly uint _secretKeyBytes;
13 | private readonly uint _bytes;
14 |
15 | public MessageSigner32()
16 | {
17 | _publicKeyBytes = PlatformInvoke32.crypto_sign_publickeybytes().ToUInt32();
18 | _secretKeyBytes = PlatformInvoke32.crypto_sign_secretkeybytes().ToUInt32();
19 | _bytes = PlatformInvoke32.crypto_sign_bytes().ToUInt32();
20 | }
21 |
22 | public SignerKeyPair CreateRandomKeyPair()
23 | {
24 | var publicKey = new byte[_publicKeyBytes];
25 | var secretKey = new byte[_secretKeyBytes];
26 | var result = PlatformInvoke32.crypto_sign_keypair(publicKey, secretKey);
27 |
28 | if (result != 0) throw new CryptographicException("Failed");
29 |
30 | return new SignerKeyPair(secretKey, publicKey);
31 | }
32 |
33 | public byte[] SignMessage(byte[] message, SignerKeyPair key)
34 | {
35 | var signedMessage = new byte[message.Length + _bytes];
36 | long signedMessageRealLength = 0;
37 |
38 | var result = PlatformInvoke32.crypto_sign(signedMessage, ref signedMessageRealLength, message, message.Length,
39 | key.SecretKeyBytes);
40 |
41 | if (result != 0) throw new CryptographicException("Failed");
42 |
43 | Array.Resize(ref signedMessage, (int)signedMessageRealLength);
44 | return signedMessage;
45 | }
46 |
47 | public byte[] VerifySignedMessage(byte[] signedMessage, SignerPublicKey publicKey)
48 | {
49 | var message = new byte[signedMessage.Length];
50 | long messageRealLength = 0;
51 |
52 | var result = PlatformInvoke32.crypto_sign_open(message, ref messageRealLength, signedMessage, signedMessage.Length,
53 | publicKey.PlainBytes);
54 |
55 | if (result != 0) throw new CryptographicException("Failed");
56 |
57 | Array.Resize(ref message, (int)messageRealLength);
58 | return message;
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/TestApp/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 | using Natrium;
7 |
8 | namespace TestApp
9 | {
10 | class Program
11 | {
12 | static void Main(string[] args)
13 | {
14 | var signingKp = PrimitiveCryptoConstructs.Instance.MessageSigner.CreateRandomKeyPair();
15 | var publicKey = signingKp.PublicKey;
16 |
17 | var messageToSign = Encoding.UTF8.GetBytes("This string should not be tampered with");
18 | var signedMessage = PrimitiveCryptoConstructs.Instance.MessageSigner.SignMessage(messageToSign, signingKp);
19 |
20 | try
21 | {
22 | var confirmedMessage = PrimitiveCryptoConstructs.Instance.MessageSigner.VerifySignedMessage(signedMessage,
23 | publicKey);
24 |
25 | Console.WriteLine("Verified message: " + Encoding.UTF8.GetString(confirmedMessage));
26 | }
27 | catch (CryptographicException)
28 | {
29 | Console.WriteLine("Signature invalid!");
30 | }
31 |
32 |
33 | var aliceKeyPair = PrimitiveCryptoConstructs.Instance.AuthenticatedPublicKeyCrypto.CreateRandomKeyPair();
34 | var alicePublicKey = aliceKeyPair.PublicKey;
35 |
36 | var bobKeyPair = PrimitiveCryptoConstructs.Instance.AuthenticatedPublicKeyCrypto.CreateRandomKeyPair();
37 | var bobPublicKey = bobKeyPair.PublicKey;
38 |
39 | var c = PrimitiveCryptoConstructs.Instance.AuthenticatedPublicKeyCrypto.CreateCrypterInstance(aliceKeyPair,
40 | bobPublicKey);
41 |
42 | // define the message and nonce
43 | var nonce = PrimitiveCryptoConstructs.Instance.AuthenticatedPublicKeyCrypto.CreateRandomNonce();
44 | var message = Encoding.UTF8.GetBytes("This string should not be read by the NSA");
45 |
46 | // encrypt
47 | var encryptedMessage = c.Encrypt(message, nonce);
48 |
49 | // decrypt on Bob's side
50 | var decryptedMessage =
51 | PrimitiveCryptoConstructs.Instance.AuthenticatedPublicKeyCrypto.VerifyAndDecryptMessage(encryptedMessage,
52 | nonce, bobKeyPair, alicePublicKey);
53 |
54 | Console.WriteLine("The message is: " + Encoding.UTF8.GetString(decryptedMessage));
55 |
56 | Console.ReadLine();
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Natrium/IAuthenticatedPublicKeyCrypto.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 |
7 | namespace Natrium
8 | {
9 | ///
10 | /// Provides methods to encrypt and authenticate data using a public-key authenticator
11 | ///
12 | public interface IAuthenticatedPublicKeyCrypto
13 | {
14 | ///
15 | /// Gets the size, in bytes, of a nonce used in encryption
16 | ///
17 | uint NonceSize { get; }
18 |
19 | ///
20 | /// Creates a new random key pair
21 | ///
22 | /// The generated key pair
23 | PublicKeyCryptoKeyPair CreateRandomKeyPair();
24 |
25 | ///
26 | /// Creates a new random nonce
27 | ///
28 | /// The generated nonce
29 | byte[] CreateRandomNonce();
30 |
31 | ///
32 | /// Encrypts and authenticates a message
33 | ///
34 | /// The message to encrypt
35 | /// An unique nonce value
36 | /// Private key pair
37 | /// The public key of the recipient of the message
38 | /// The encrypted message
39 | byte[] EncryptMessage(byte[] message, byte[] nonce, PublicKeyCryptoKeyPair key, PublicKeyCryptoPublicKey recipientPublicKey);
40 |
41 | ///
42 | /// Verifies and decrypts a message
43 | ///
44 | /// The encrypted message
45 | /// The nonce value used to encrypt the message
46 | /// Private key pair
47 | /// The public key of the sender
48 | /// The decrypted message
49 | /// Thrown if integrity of the decrypted data cannot be confirmed
50 | byte[] VerifyAndDecryptMessage(byte[] encryptedMessage, byte[] nonce, PublicKeyCryptoKeyPair key, PublicKeyCryptoPublicKey senderPublicKey);
51 |
52 | ///
53 | /// Creates a multi-use crypter instance using the specified keys
54 | ///
55 | /// Private key pair
56 | /// The public key of the other side
57 | /// A crypter context with the key parameters set
58 | IAuthenticatedPublicKeyCryptoContext CreateCrypterInstance(PublicKeyCryptoKeyPair key, PublicKeyCryptoPublicKey publicKey);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/TestApp/TestApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {2F1A30AE-A44D-4C9E-A693-1C29B97E4412}
8 | Exe
9 | Properties
10 | TestApp
11 | TestApp
12 | v4.0
13 | 512
14 |
15 |
16 | x86
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | {f16c829b-c9c9-4968-92da-711eb0bb1071}
50 | NSodium
51 |
52 |
53 |
54 |
61 |
--------------------------------------------------------------------------------
/Natrium/Natrium.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {F16C829B-C9C9-4968-92DA-711EB0BB1071}
8 | Library
9 | Properties
10 | Natrium
11 | Natrium
12 | v4.0
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 | AnyCPU
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
68 |
--------------------------------------------------------------------------------
/Natrium/PrimitiveCryptoConstructs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Natrium
4 | {
5 | ///
6 | /// Provides access to various cryptographic constructs
7 | ///
8 | public class PrimitiveCryptoConstructs
9 | {
10 | // Singleton instance because sodium_init must be called once
11 | // Lazy-loading is utilized for all members
12 |
13 | private static readonly Lazy _instance = new Lazy(() => new PrimitiveCryptoConstructs());
14 |
15 | ///
16 | /// Gets the singleton instance of the class
17 | ///
18 | public static PrimitiveCryptoConstructs Instance
19 | {
20 | get { return _instance.Value; }
21 | }
22 |
23 | private PrimitiveCryptoConstructs()
24 | {
25 | if (Environment.Is64BitProcess)
26 | {
27 | PlatformInvoke64.sodium_init();
28 | }
29 | else
30 | {
31 | PlatformInvoke32.sodium_init();
32 | }
33 | }
34 |
35 | private readonly Lazy _authenticatedPublicKeyCrypto =
36 | new Lazy(() =>
37 | {
38 | if (Environment.Is64BitProcess)
39 | {
40 | return new AuthenticatedPublicKeyCrypto64();
41 | }
42 | else
43 | {
44 | return new AuthenticatedPublicKeyCrypto32();
45 | }
46 | });
47 |
48 | ///
49 | /// Gets an instance of a class for encrypting and decrypting messages using public-key cryptography
50 | ///
51 | public IAuthenticatedPublicKeyCrypto AuthenticatedPublicKeyCrypto
52 | {
53 | get { return _authenticatedPublicKeyCrypto.Value; }
54 | }
55 |
56 | private readonly Lazy _messageSigner =
57 | new Lazy(() =>
58 | {
59 | if (Environment.Is64BitProcess)
60 | {
61 | return new MessageSigner64();
62 | }
63 | else
64 | {
65 | return new MessageSigner32();
66 | }
67 | });
68 |
69 | ///
70 | /// Gets an instance of a class for digitally signing and verifying messages
71 | ///
72 | public IMessageSigner MessageSigner
73 | {
74 | get { return _messageSigner.Value; }
75 | }
76 |
77 | private readonly Lazy _rng =
78 | new Lazy(() =>
79 | {
80 | if (Environment.Is64BitProcess)
81 | {
82 | return new RandomNumberGenerator64();
83 | }
84 | else
85 | {
86 | return new RandomNumberGenerator32();
87 | }
88 | });
89 |
90 | ///
91 | /// Gets an instance of a cryptographically secure pseudo-random number generator (CSPRNG)
92 | ///
93 | public IRandomNumberGenerator Rng
94 | {
95 | get { return _rng.Value; }
96 | }
97 |
98 |
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/Natrium/PlatformInvoke64.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace Natrium
5 | {
6 | internal static class PlatformInvoke64
7 | {
8 | private const string LibraryName = "libsodium-64.dll";
9 |
10 |
11 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
12 | public static extern void sodium_init();
13 |
14 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
15 | public static extern UIntPtr crypto_box_publickeybytes();
16 |
17 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
18 | public static extern UIntPtr crypto_box_secretkeybytes();
19 |
20 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
21 | public static extern UIntPtr crypto_box_noncebytes();
22 |
23 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
24 | public static extern UIntPtr crypto_box_zerobytes();
25 |
26 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
27 | public static extern UIntPtr crypto_box_beforenmbytes();
28 |
29 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
30 | public static extern int crypto_box_keypair(byte[] publicKey, byte[] secretKey);
31 |
32 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
33 | public static extern int crypto_box(byte[] buffer, byte[] message, long messageLength, byte[] nonce, byte[] publicKey, byte[] secretKey);
34 |
35 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
36 | public static extern int crypto_box_beforenm(byte[] sharedSecret, byte[] publicKey, byte[] secretKey);
37 |
38 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
39 | public static extern int crypto_box_afternm(byte[] buffer, byte[] message, long messageLength, byte[] nonce, byte[] sharedSecret);
40 |
41 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
42 | public static extern int crypto_box_open(byte[] buffer, byte[] cipherText, long cipherTextLength, byte[] nonce, byte[] publicKey, byte[] secretKey);
43 |
44 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
45 | public static extern int crypto_box_open_afternm(byte[] buffer, byte[] cipherText, long cipherTextLength, byte[] nonce, byte[] sharedSecret);
46 |
47 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
48 | public static extern void randombytes_buf(byte[] buffer, UIntPtr size);
49 |
50 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
51 | public static extern UIntPtr crypto_sign_publickeybytes();
52 |
53 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
54 | public static extern UIntPtr crypto_sign_secretkeybytes();
55 |
56 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
57 | public static extern UIntPtr crypto_sign_bytes();
58 |
59 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
60 | public static extern int crypto_sign_keypair(byte[] publicKey, byte[] secretKey);
61 |
62 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
63 | public static extern int crypto_sign(byte[] sig, ref long sigLength, byte[] message, long messageLength, byte[] secretKey);
64 |
65 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
66 | public static extern int crypto_sign_open(byte[] message, ref long messageLength, byte[] sig, long sigLength, byte[] publicKey);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Natrium/PlatformInvoke32.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace Natrium
5 | {
6 | internal static class PlatformInvoke32
7 | {
8 | private const string LibraryName = "libsodium-32.dll";
9 |
10 |
11 |
12 |
13 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
14 | public static extern void sodium_init();
15 |
16 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
17 | public static extern UIntPtr crypto_box_publickeybytes();
18 |
19 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
20 | public static extern UIntPtr crypto_box_secretkeybytes();
21 |
22 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
23 | public static extern UIntPtr crypto_box_noncebytes();
24 |
25 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
26 | public static extern UIntPtr crypto_box_zerobytes();
27 |
28 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
29 | public static extern UIntPtr crypto_box_beforenmbytes();
30 |
31 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
32 | public static extern int crypto_box_keypair(byte[] publicKey, byte[] secretKey);
33 |
34 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
35 | public static extern int crypto_box(byte[] buffer, byte[] message, long messageLength, byte[] nonce, byte[] publicKey, byte[] secretKey);
36 |
37 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
38 | public static extern int crypto_box_beforenm(byte[] sharedSecret, byte[] publicKey, byte[] secretKey);
39 |
40 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
41 | public static extern int crypto_box_afternm(byte[] buffer, byte[] message, long messageLength, byte[] nonce, byte[] sharedSecret);
42 |
43 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
44 | public static extern int crypto_box_open(byte[] buffer, byte[] cipherText, long cipherTextLength, byte[] nonce, byte[] publicKey, byte[] secretKey);
45 |
46 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
47 | public static extern int crypto_box_open_afternm(byte[] buffer, byte[] cipherText, long cipherTextLength, byte[] nonce, byte[] sharedSecret);
48 |
49 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
50 | public static extern void randombytes_buf(byte[] buffer, UIntPtr size);
51 |
52 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
53 | public static extern UIntPtr crypto_sign_publickeybytes();
54 |
55 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
56 | public static extern UIntPtr crypto_sign_secretkeybytes();
57 |
58 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
59 | public static extern UIntPtr crypto_sign_bytes();
60 |
61 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
62 | public static extern int crypto_sign_keypair(byte[] publicKey, byte[] secretKey);
63 |
64 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
65 | public static extern int crypto_sign(byte[] sig, ref long sigLength, byte[] message, long messageLength, byte[] secretKey);
66 |
67 | [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
68 | public static extern int crypto_sign_open(byte[] message, ref long messageLength, byte[] sig, long sigLength, byte[] publicKey);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Natrium/AuthenticatedPublicKeyCrypto32.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Cryptography;
3 |
4 | namespace Natrium
5 | {
6 | internal sealed class AuthenticatedPublicKeyCrypto32 : IAuthenticatedPublicKeyCrypto
7 | {
8 | private readonly uint _publicKeyBytes;
9 | private readonly uint _secretKeyBytes;
10 | private readonly uint _zeroBytes;
11 | private readonly uint _beforeNmBytes;
12 |
13 | public AuthenticatedPublicKeyCrypto32()
14 | {
15 | _publicKeyBytes = PlatformInvoke32.crypto_box_publickeybytes().ToUInt32();
16 | _secretKeyBytes = PlatformInvoke32.crypto_box_secretkeybytes().ToUInt32();
17 | _zeroBytes = PlatformInvoke32.crypto_box_zerobytes().ToUInt32();
18 | _beforeNmBytes = PlatformInvoke32.crypto_box_beforenmbytes().ToUInt32();
19 | NonceSize = PlatformInvoke32.crypto_box_noncebytes().ToUInt32();
20 | }
21 |
22 | public uint NonceSize { get; private set; }
23 |
24 | public PublicKeyCryptoKeyPair CreateRandomKeyPair()
25 | {
26 | var publicKey = new byte[_publicKeyBytes];
27 | var secretKey = new byte[_secretKeyBytes];
28 | var result = PlatformInvoke32.crypto_box_keypair(publicKey, secretKey);
29 |
30 | if (result != 0) throw new CryptographicException("Failed");
31 |
32 | return new PublicKeyCryptoKeyPair(secretKey, publicKey);
33 | }
34 |
35 | public byte[] CreateRandomNonce()
36 | {
37 | var nonce = new byte[NonceSize];
38 | PlatformInvoke32.randombytes_buf(nonce, new UIntPtr((uint)nonce.Length));
39 |
40 | return nonce;
41 | }
42 |
43 | public byte[] EncryptMessage(byte[] message, byte[] nonce, PublicKeyCryptoKeyPair key, PublicKeyCryptoPublicKey recipientPublicKey)
44 | {
45 | // verify arguments
46 | if (nonce == null) throw new ArgumentNullException("nonce");
47 | if (nonce.Length != NonceSize)
48 | throw new ArgumentOutOfRangeException("nonce", string.Format("Nonce must be {0} bytes long", NonceSize));
49 |
50 | // pad the message (prepend zero bytes)
51 | var paddedMessage = new byte[_zeroBytes + message.Length];
52 | Buffer.BlockCopy(message, 0, paddedMessage, (int)_zeroBytes, message.Length);
53 |
54 | // encrypt
55 | var encryptedMessage = new byte[paddedMessage.Length];
56 | var result = PlatformInvoke32.crypto_box(encryptedMessage, paddedMessage, paddedMessage.Length, nonce, recipientPublicKey.PlainBytes,
57 | key.SecretKeyBytes);
58 |
59 | if (result != 0) throw new CryptographicException("Failed");
60 |
61 | return encryptedMessage;
62 | }
63 |
64 | public byte[] VerifyAndDecryptMessage(byte[] encryptedMessage, byte[] nonce, PublicKeyCryptoKeyPair key, PublicKeyCryptoPublicKey senderPublicKey)
65 | {
66 | // verify arguments
67 | if (nonce == null) throw new ArgumentNullException("nonce");
68 | if (nonce.Length != NonceSize)
69 | throw new ArgumentOutOfRangeException("nonce", string.Format("Nonce must be {0} bytes long", NonceSize));
70 |
71 | // decrypt
72 | var paddedMessage = new byte[encryptedMessage.Length];
73 | var result = PlatformInvoke32.crypto_box_open(paddedMessage, encryptedMessage, encryptedMessage.Length, nonce,
74 | senderPublicKey.PlainBytes, key.SecretKeyBytes);
75 |
76 | if (result != 0) throw new CryptographicException("Failed");
77 |
78 | var message = new byte[paddedMessage.Length - _zeroBytes];
79 | Buffer.BlockCopy(paddedMessage, (int)_zeroBytes, message, 0, message.Length);
80 |
81 | return message;
82 | }
83 |
84 | public IAuthenticatedPublicKeyCryptoContext CreateCrypterInstance(PublicKeyCryptoKeyPair key, PublicKeyCryptoPublicKey publicKey)
85 | {
86 | // compute the shared secret
87 | var sharedSecret = new byte[_beforeNmBytes];
88 | var result = PlatformInvoke32.crypto_box_beforenm(sharedSecret, publicKey.PlainBytes, key.SecretKeyBytes);
89 |
90 | if (result != 0) throw new CryptographicException("Failed");
91 |
92 | return new AuthenticatedPublicKeyCryptoContext(this, sharedSecret);
93 | }
94 |
95 | private class AuthenticatedPublicKeyCryptoContext : IAuthenticatedPublicKeyCryptoContext, IDisposable
96 | {
97 | private readonly AuthenticatedPublicKeyCrypto32 _parent;
98 | private readonly byte[] _sharedSecret;
99 |
100 | public AuthenticatedPublicKeyCryptoContext(AuthenticatedPublicKeyCrypto32 parent, byte[] sharedSecret)
101 | {
102 | _parent = parent;
103 | _sharedSecret = sharedSecret;
104 | }
105 |
106 | public void Dispose()
107 | {
108 | Array.Clear(_sharedSecret, 0, _sharedSecret.Length);
109 | }
110 |
111 | public byte[] Encrypt(byte[] message, byte[] nonce)
112 | {
113 | // verify arguments
114 | if (nonce == null) throw new ArgumentNullException("nonce");
115 | if (nonce.Length != _parent.NonceSize)
116 | throw new ArgumentOutOfRangeException("nonce", string.Format("Nonce must be {0} bytes long", _parent.NonceSize));
117 |
118 |
119 | // pad the message (prepend zero bytes)
120 | var paddedMessage = new byte[_parent._zeroBytes + message.Length];
121 | Buffer.BlockCopy(message, 0, paddedMessage, (int)_parent._zeroBytes, message.Length);
122 |
123 | // encrypt
124 | var encryptedMessage = new byte[paddedMessage.Length];
125 | var result = PlatformInvoke32.crypto_box_afternm(encryptedMessage, paddedMessage, paddedMessage.Length, nonce, _sharedSecret);
126 |
127 | if (result != 0) throw new CryptographicException("Failed");
128 |
129 | return encryptedMessage;
130 | }
131 |
132 | public byte[] VerifyAndDecrypt(byte[] encryptedMessage, byte[] nonce)
133 | {
134 | // verify arguments
135 | if (nonce == null) throw new ArgumentNullException("nonce");
136 | if (nonce.Length != _parent.NonceSize)
137 | throw new ArgumentOutOfRangeException("nonce", string.Format("Nonce must be {0} bytes long", _parent.NonceSize));
138 |
139 |
140 | // decrypt
141 | var paddedMessage = new byte[encryptedMessage.Length];
142 | var result = PlatformInvoke32.crypto_box_open_afternm(paddedMessage, encryptedMessage, encryptedMessage.Length, nonce, _sharedSecret);
143 |
144 | if (result != 0) throw new CryptographicException("Failed");
145 |
146 | var message = new byte[paddedMessage.Length - _parent._zeroBytes];
147 | Buffer.BlockCopy(paddedMessage, (int)_parent._zeroBytes, message, 0, message.Length);
148 |
149 | return message;
150 | }
151 |
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/Natrium/AuthenticatedPublicKeyCrypto64.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Security.Cryptography;
3 |
4 | namespace Natrium
5 | {
6 | internal sealed class AuthenticatedPublicKeyCrypto64 : IAuthenticatedPublicKeyCrypto
7 | {
8 | private readonly uint _publicKeyBytes;
9 | private readonly uint _secretKeyBytes;
10 | private readonly uint _zeroBytes;
11 | private readonly uint _beforeNmBytes;
12 |
13 | public AuthenticatedPublicKeyCrypto64()
14 | {
15 | _publicKeyBytes = PlatformInvoke64.crypto_box_publickeybytes().ToUInt32();
16 | _secretKeyBytes = PlatformInvoke64.crypto_box_secretkeybytes().ToUInt32();
17 | _zeroBytes = PlatformInvoke64.crypto_box_zerobytes().ToUInt32();
18 | _beforeNmBytes = PlatformInvoke64.crypto_box_beforenmbytes().ToUInt32();
19 | NonceSize = PlatformInvoke64.crypto_box_noncebytes().ToUInt32();
20 | }
21 |
22 | public uint NonceSize { get; private set; }
23 |
24 | public PublicKeyCryptoKeyPair CreateRandomKeyPair()
25 | {
26 | var publicKey = new byte[_publicKeyBytes];
27 | var secretKey = new byte[_secretKeyBytes];
28 | var result = PlatformInvoke64.crypto_box_keypair(publicKey, secretKey);
29 |
30 | if (result != 0) throw new CryptographicException("Failed");
31 |
32 | return new PublicKeyCryptoKeyPair(secretKey, publicKey);
33 | }
34 |
35 | public byte[] CreateRandomNonce()
36 | {
37 | var nonce = new byte[NonceSize];
38 | PlatformInvoke64.randombytes_buf(nonce, new UIntPtr((uint)nonce.Length));
39 |
40 | return nonce;
41 | }
42 |
43 | public byte[] EncryptMessage(byte[] message, byte[] nonce, PublicKeyCryptoKeyPair key, PublicKeyCryptoPublicKey recipientPublicKey)
44 | {
45 | // verify arguments
46 | if (nonce == null) throw new ArgumentNullException("nonce");
47 | if (nonce.Length != NonceSize)
48 | throw new ArgumentOutOfRangeException("nonce", string.Format("Nonce must be {0} bytes long", NonceSize));
49 |
50 | // pad the message (prepend zero bytes)
51 | var paddedMessage = new byte[_zeroBytes + message.Length];
52 | Buffer.BlockCopy(message, 0, paddedMessage, (int)_zeroBytes, message.Length);
53 |
54 | // encrypt
55 | var encryptedMessage = new byte[paddedMessage.Length];
56 | var result = PlatformInvoke64.crypto_box(encryptedMessage, paddedMessage, paddedMessage.Length, nonce, recipientPublicKey.PlainBytes,
57 | key.SecretKeyBytes);
58 |
59 | if (result != 0) throw new CryptographicException("Failed");
60 |
61 | return encryptedMessage;
62 | }
63 |
64 | public byte[] VerifyAndDecryptMessage(byte[] encryptedMessage, byte[] nonce, PublicKeyCryptoKeyPair key, PublicKeyCryptoPublicKey senderPublicKey)
65 | {
66 | // verify arguments
67 | if (nonce == null) throw new ArgumentNullException("nonce");
68 | if (nonce.Length != NonceSize)
69 | throw new ArgumentOutOfRangeException("nonce", string.Format("Nonce must be {0} bytes long", NonceSize));
70 |
71 | // decrypt
72 | var paddedMessage = new byte[encryptedMessage.Length];
73 | var result = PlatformInvoke64.crypto_box_open(paddedMessage, encryptedMessage, encryptedMessage.Length, nonce,
74 | senderPublicKey.PlainBytes, key.SecretKeyBytes);
75 |
76 | if (result != 0) throw new CryptographicException("Failed");
77 |
78 | var message = new byte[paddedMessage.Length - _zeroBytes];
79 | Buffer.BlockCopy(paddedMessage, (int)_zeroBytes, message, 0, message.Length);
80 |
81 | return message;
82 | }
83 |
84 | public IAuthenticatedPublicKeyCryptoContext CreateCrypterInstance(PublicKeyCryptoKeyPair key, PublicKeyCryptoPublicKey publicKey)
85 | {
86 | // compute the shared secret
87 | var sharedSecret = new byte[_beforeNmBytes];
88 | var result = PlatformInvoke64.crypto_box_beforenm(sharedSecret, publicKey.PlainBytes, key.SecretKeyBytes);
89 |
90 | if (result != 0) throw new CryptographicException("Failed");
91 |
92 | return new AuthenticatedPublicKeyCryptoContext(this, sharedSecret);
93 | }
94 |
95 | private class AuthenticatedPublicKeyCryptoContext : IAuthenticatedPublicKeyCryptoContext, IDisposable
96 | {
97 | private readonly AuthenticatedPublicKeyCrypto64 _parent;
98 | private readonly byte[] _sharedSecret;
99 |
100 | public AuthenticatedPublicKeyCryptoContext(AuthenticatedPublicKeyCrypto64 parent, byte[] sharedSecret)
101 | {
102 | _parent = parent;
103 | _sharedSecret = sharedSecret;
104 | }
105 |
106 | public void Dispose()
107 | {
108 | Array.Clear(_sharedSecret, 0, _sharedSecret.Length);
109 | }
110 |
111 | public byte[] Encrypt(byte[] message, byte[] nonce)
112 | {
113 | // verify arguments
114 | if (nonce == null) throw new ArgumentNullException("nonce");
115 | if (nonce.Length != _parent.NonceSize)
116 | throw new ArgumentOutOfRangeException("nonce", string.Format("Nonce must be {0} bytes long", _parent.NonceSize));
117 |
118 |
119 | // pad the message (prepend zero bytes)
120 | var paddedMessage = new byte[_parent._zeroBytes + message.Length];
121 | Buffer.BlockCopy(message, 0, paddedMessage, (int)_parent._zeroBytes, message.Length);
122 |
123 | // encrypt
124 | var encryptedMessage = new byte[paddedMessage.Length];
125 | var result = PlatformInvoke64.crypto_box_afternm(encryptedMessage, paddedMessage, paddedMessage.Length, nonce, _sharedSecret);
126 |
127 | if (result != 0) throw new CryptographicException("Failed");
128 |
129 | return encryptedMessage;
130 | }
131 |
132 | public byte[] VerifyAndDecrypt(byte[] encryptedMessage, byte[] nonce)
133 | {
134 | // verify arguments
135 | if (nonce == null) throw new ArgumentNullException("nonce");
136 | if (nonce.Length != _parent.NonceSize)
137 | throw new ArgumentOutOfRangeException("nonce", string.Format("Nonce must be {0} bytes long", _parent.NonceSize));
138 |
139 |
140 | // decrypt
141 | var paddedMessage = new byte[encryptedMessage.Length];
142 | var result = PlatformInvoke64.crypto_box_open_afternm(paddedMessage, encryptedMessage, encryptedMessage.Length, nonce, _sharedSecret);
143 |
144 | if (result != 0) throw new CryptographicException("Failed");
145 |
146 | var message = new byte[paddedMessage.Length - _parent._zeroBytes];
147 | Buffer.BlockCopy(paddedMessage, (int)_parent._zeroBytes, message, 0, message.Length);
148 |
149 | return message;
150 | }
151 |
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------