Giter VIP home page Giter VIP logo

nacl.core's Introduction

NaCl.Core, a cryptography library for .NET

Build Status CI Build status contributions welcome

Introduction

NaCl.Core is a managed-only cryptography library for .NET which provides modern cryptographic primitives.

Currently supported:

Crypto Description
Salsa20 A high-speed stream cipher part of the family of 256-bit stream ciphers designed in 2005 and submitted to eSTREAM, the ECRYPT Stream Cipher Project
ChaCha20 A high-speed stream cipher based on Salsa20
XChaCha20 Based on ChaCha20 IETF with extended nonce (192-bit instead of 96-bit)
Poly1305 A state-of-the-art secret-key message-authentication code (MAC) based on RFC8439
ChaCha20Poly1305 An Authenticated Encryption with Associated Data (AEAD) algorithm; IETF variant as defined in RFC8439 and in its predecessor RFC7539
XChaCha20Poly1305 A variant of ChaCha20-Poly1305 that utilizes the XChaCha20 construction in place of ChaCha20; as defined in the RFC Draft

Installation

NuGet CI NuGet

Install the NaCl.Core NuGet package from the .NET CLI using:

dotnet add package NaCl.Core

or from the NuGet package manager:

Install-Package NaCl.Core

Or alternatively, you can add the NaCl.Core package from within Visual Studio's NuGet package manager.

Daily NuGet builds of the project are also available in the Azure Artifacts feed:

https://pkgs.dev.azure.com/idaviddesmet/NaCl.Core/_packaging/NaCl.Core-CI/nuget/v3/index.json

Usage

Symmetric Key Encryption

// Create the primitive
var aead = new ChaCha20Poly1305(key);

// Use the primitive to encrypt a plaintext
aead.Encrypt(nonce, plaintext, ciphertext, tag, aad);

// ... or to decrypt a ciphertext
aead.Decrypt(nonce, ciphertext, tag, plaintext, aad);

MAC (Message Authentication Code)

// Use the primitive to compute a tag
Poly1305.ComputeMac(key, data, tag);

// ... or to verify a tag
Poly1305.VerifyMac(key, data, tag);

Test Coverage

Azure DevOps tests Azure DevOps coverage codecov

  • Includes the mandatory RFC test vectors.
  • Project Wycheproof by members of Google Security Team, for testing against known attacks (when applicable).

Learn More

License

nacl.core's People

Contributors

azure-pipelines[bot] avatar daviddesmet avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar moien007 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

nacl.core's Issues

Improve Azure Pipelines when pushing Artifacts

Skip duplicates when pushing a NuGet package to Azure Artifacts by passing true to allowPackageConflicts.

  - task: NuGetCommand@2
    displayName: 'Push NuGet'
    inputs:
      command: 'push'
      packagesToPush: '$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg'
      nuGetFeedType: 'internal'
      publishVstsFeed: 'ffbd9fd0-ffca-4040-8576-0fa5065bd6d9/b465c74e-3671-458e-996f-8bbf45f957bc'
      allowPackageConflicts: true

Will you add support for AES-GCM and AES-CCM ciphers?

Microsoft have added support for AES-GCM and AES-CCM ciphers, implemented via System.Security.Cryptography.AesGcm and System.Security.Cryptography.AesCcm. These algorithms are the first Authenticated Encryption (AE) algorithms added to .NET Core 3.0 (starting from Preview 1). Since it will be supported out-of-the-box, I don't see the benefit of adding support for those.

The following code demonstrates using AesGcm cipher to encrypt and decrypt random data. The code for AesCcm would look almost identical (only the class variable names would be different):

// key should be: pre-known, derived, or transported via another channel, such as RSA encryption
byte[] key = new byte[16];
RandomNumberGenerator.Fill(key);

byte[] nonce = new byte[12];
RandomNumberGenerator.Fill(nonce);

// normally this would be your data
byte[] dataToEncrypt = new byte[1234];
byte[] associatedData = new byte[333];
RandomNumberGenerator.Fill(dataToEncrypt);
RandomNumberGenerator.Fill(associatedData);

// these will be filled during the encryption
byte[] tag = new byte[16];
byte[] ciphertext = new byte[dataToEncrypt.Length];

using (AesGcm aesGcm = new AesGcm(key))
{
    aesGcm.Encrypt(nonce, dataToEncrypt, ciphertext, tag, associatedData);
}

// tag, nonce, ciphertext, associatedData should be sent to the other part

byte[] decryptedData = new byte[ciphertext.Length];

using (AesGcm aesGcm = new AesGcm(key))
{
    aesGcm.Decrypt(nonce, ciphertext, tag, decryptedData, associatedData);
}

// do something with the data
// this should always print that data is the same
Console.WriteLine($"AES-GCM: Decrypted data is{(dataToEncrypt.SequenceEqual(decryptedData) ? "the same as" : "different than")} original data.");

Unit Testing with Linux agents are taking longer to complete

Testing should be taking around 2 minutes but is taking longer than usual on Linux.
I had the same issue with another project when running against SDK 2.2.300 as specified here and here.

GitHub Actions CI result:

Test Run Successful.
Total tests: 121
     Passed: 121
 Total time: 7.7948 Minutes

Azure DevOps CI result:

Total tests: 121. Passed: 121. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution time: 8.5036 Minutes

AppVeyor CI result (it took longer than it reports):

Test Run Successful.
Total tests: 121
     Passed: 121
 Total time: 2.2034 Minutes

Binary endianness safety

Hi,

The class ByteIntegerConverter have methods like LoadLittleEndian32 and StoreLittleEndian32 which is not checking for system endianness (which is not guaranteed to be little-endian in .NET). In the old .NET days, we were checking System.BitConverter.IsLittleEndian field to finding out system endianness and reversing the bytes to achieve the endianness that we were looking for, but in this modern .NET age we should consider using System.Buffers.BinaryPrimitives class (my benchmarks showed me it is significantly faster than bitwise operations like << and || since it takes advantage of CPU instructions like rotl and rotr on X86 machines).

Does the MAC need a nonce?

When I read the authoritative source:
https://cr.yp.to/mac.html

It talks of a 16 byte nonce for Poly1305 MACs.

Using the code below to generate MACs, where is the nonce involved?

// Use the primitive to compute a tag
var tag = Poly1305.ComputeMac(key, data);

// ... or to verify a tag
Poly1305.VerifyMac(key, data, tag);

Thanks.

Make final classes 'sealed'

Hi,

Making the classes that are not going to become base classes like XChaCha20Poly1305 class
sealed results in better performance as the virtual method calls become direct method calls.
Also, I have to point out this is a breaking change.

Regards.

System.Runtime.Intrinsics.X86

Hello,

My library that uses NaCl.Core has 2 variants, one that uses NaCl.Core, and the other that uses the libsodium native library. The libsodium variant runs 4 times faster, but has deployment pitfalls where you have to ensure the correct native file is used for the processor architecture and OS. I've worked around those pitfalls but it got me wondering about optimization in NaCl.Core as a fully managed solution has less friction.

I was wondering if you had looked at the System.Runtime.Intrinsics.X86 namespace in .NET Core 3.0?

I am new to intrinsics so don't consider the following to be authoritative but I thought I'd present my experience as a data point for using intrinsics.

XOR proof-of-concept

I did a proof of concept on an easy bit to update - the XOR in Snuffle.cs (this doesn't improve performance much).

At the top:

#if NETCOREAPP3_0
    using System.Runtime.Intrinsics;
    using System.Runtime.Intrinsics.X86;
#endif

In Process:

            using (var owner = MemoryPool<byte>.Shared.Rent(BLOCK_SIZE_IN_BYTES))
            {
                for (var i = 0; i < numBlocks; i++)
                {
                    ProcessKeyStreamBlock(nonce, i + InitialCounter, owner.Memory.Span);

#if NETCOREAPP3_0
                    if (i == numBlocks - 1)
                        Xor(output, input, owner.Memory.Span, length % BLOCK_SIZE_IN_BYTES, offset, i); // last block
                    else
                        XorIntrinsic(output, input, owner.Memory.Span, BLOCK_SIZE_IN_BYTES, offset, i);
#else
                    if (i == numBlocks - 1)
                        Xor(output, input, owner.Memory.Span, length % BLOCK_SIZE_IN_BYTES, offset, i); // last block
                    else
                        Xor(output, input, owner.Memory.Span, BLOCK_SIZE_IN_BYTES, offset, i);
#endif

                    owner.Memory.Span.Clear();
                }
            }

New method at the bottom:

#if NETCOREAPP3_0
        private static unsafe void XorIntrinsic(Span<byte> output, ReadOnlySpan<byte> input, ReadOnlySpan<byte> block, int len, int offset, int curBlock)
        {
            var blockOffset = curBlock * BLOCK_SIZE_IN_BYTES;

            //To do - input length validation checks
            fixed (byte* pOut = output, pInA = input, pInB = block)
            {
                byte* pOutEnd = pOut + offset + blockOffset + len;
                byte* pOutCurrent = pOut + offset + blockOffset;
                byte* pInACurrent = pInA + blockOffset;
                byte* pInBCurrent = pInB;

                while (pOutCurrent + 8 <= pOutEnd)
                {
                    var inputAVector = Avx.LoadVector256(pInACurrent);
                    var inputBVector = Avx.LoadVector256(pInBCurrent);
                    var outputVector = Avx2.Xor(inputAVector, inputBVector);
                    Avx.Store(pOutCurrent, outputVector);

                    pOutCurrent += 8;
                    pInACurrent += 8;
                    pInBCurrent += 8;
                }
            }
        }
#endif

That compiled and benchmarked successfully, running approximately the same speed, perhaps a tiny amount faster.

Conclusion

It seems that to fully implement intrinsics in the Snuffle.cs class (and hence get large performance gains) ProcessKeyStreamBlock would be the place to start, and hence the implementation of u0.h/u1.h/u4.h/u8.h in this directory.

Whilst I don't have the bandwidth for a pull request that is a mass update to include intrinsics, if you were to establish a style/methodology for including intrinsics, I could contribute in parts when time allows.

Match signature of new Core APIs?

There is a new System.Security.Cryptography.AesGcm API in .NET Core, it might be beneficial to add the same method signatures into NaCl.Core.

Note: this new API seems to interop to native OS libraries, I'm intrigued to see how they compare against the intrinsic-optimised NaCl.Core, so I will probably try this at some point.

Unsure about SnufflePoly1305 Decrypt

Hello,

I'm trying to use your code on small buffers for network encryption and the Decrypt function throws a CryptographyException "The ciphertext is too short."

I compared it to other ChaCha20Poly1305 implementations and removed the _snuffle.NonceSizeInBytes(). I'm not even close to understanding the consequences but all your unit tests are still working as expected.

Is it safe to use the code that way?

Example:

public struct KeepAlivePacket {
    public uint clientIndex;
    public uint maxClients;
}


//in unit test
var packet = new KeepAlivePacket {
    clientIndex = 0,
    maxClients = 6
};

byte[] key = ByteUtils.Generate256BitKey();
byte[] add = EncryptionHelper.CreateAdditionalData(...);
byte[] nonce = EncryptionHelper.CreateNonce(...);

var chacha = new ChaCha20Poly1305(key);

byte[] encrypted = chacha.Encrypt(packetBuffer, additionalData, nonce);
byte[] decrypted = chacha.Decrypt(encrypted, additionalData, nonce);

I'd love to get a reply,
Cheers

Fix the constructor of Snuffle base class

The Snuffle base class's constructor's first parameter is in byte[] key which doesn't make sense, in is same as ref keyword (which means a reference to the specified value rather than value itself as you know) with the difference that in doesn't allow modifications to the value that being referenced (at the language level).

https://github.com/idaviddesmet/NaCl.Core/blob/54372a2914d9f770d1bd3c42898fb17928f57a28/src/NaCl.Core/Base/Snuffle.cs#L40

So what is happening here in this constructor is that we are passing a reference to a byte array (which arrays are references too) so the goal we are looking for (a read-only input or const char *key in C) is not achieved here. In order to fix this problem, we have to replace the in byte[] key with ReadOnlyMemory<byte> key which introduces a lot of changes in the code plus it is a breaking change.

Regards.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.