Skip to content

Commit

Permalink
Implement ChaCha20Poly1305 with CryptoKit on macOS
Browse files Browse the repository at this point in the history
Co-authored-by: Filip Navara <filip.navara@gmail.com>
  • Loading branch information
vcsjones and filipnavara authored Oct 1, 2022
1 parent 65a1578 commit 72ac50c
Show file tree
Hide file tree
Showing 10 changed files with 354 additions and 4 deletions.
2 changes: 1 addition & 1 deletion eng/native/configurecompiler.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,7 @@ if (CLR_CMAKE_HOST_UNIX)
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0")
add_compile_options(-arch arm64)
elseif(CLR_CMAKE_HOST_ARCH_AMD64)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15")
add_compile_options(-arch x86_64)
else()
clr_unknown_arch()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.Apple;

internal static partial class Interop
{
internal static partial class AppleCrypto
{
internal static unsafe void ChaCha20Poly1305Encrypt(
ReadOnlySpan<byte> key,
ReadOnlySpan<byte> nonce,
ReadOnlySpan<byte> plaintext,
Span<byte> ciphertext,
Span<byte> tag,
ReadOnlySpan<byte> aad)
{
fixed (byte* keyPtr = key)
fixed (byte* noncePtr = nonce)
fixed (byte* plaintextPtr = plaintext)
fixed (byte* ciphertextPtr = ciphertext)
fixed (byte* tagPtr = tag)
fixed (byte* aadPtr = aad)
{
const int Success = 1;
int result = AppleCryptoNative_ChaCha20Poly1305Encrypt(
keyPtr, key.Length,
noncePtr, nonce.Length,
plaintextPtr, plaintext.Length,
ciphertextPtr, ciphertext.Length,
tagPtr, tag.Length,
aadPtr, aad.Length);

if (result != Success)
{
Debug.Assert(result == 0);
CryptographicOperations.ZeroMemory(ciphertext);
CryptographicOperations.ZeroMemory(tag);
throw new CryptographicException();
}
}
}

internal static unsafe void ChaCha20Poly1305Decrypt(
ReadOnlySpan<byte> key,
ReadOnlySpan<byte> nonce,
ReadOnlySpan<byte> ciphertext,
ReadOnlySpan<byte> tag,
Span<byte> plaintext,
ReadOnlySpan<byte> aad)
{
fixed (byte* keyPtr = key)
fixed (byte* noncePtr = nonce)
fixed (byte* ciphertextPtr = ciphertext)
fixed (byte* tagPtr = tag)
fixed (byte* plaintextPtr = plaintext)
fixed (byte* aadPtr = aad)
{
const int Success = 1;
const int AuthTagMismatch = -1;
int result = AppleCryptoNative_ChaCha20Poly1305Decrypt(
keyPtr, key.Length,
noncePtr, nonce.Length,
ciphertextPtr, ciphertext.Length,
tagPtr, tag.Length,
plaintextPtr, plaintext.Length,
aadPtr, aad.Length);

if (result != Success)
{
CryptographicOperations.ZeroMemory(plaintext);

if (result == AuthTagMismatch)
{
throw new AuthenticationTagMismatchException();
}
else
{
Debug.Assert(result == 0);
throw new CryptographicException();
}
}
}
}

[LibraryImport(Libraries.AppleCryptoNative)]
private static unsafe partial int AppleCryptoNative_ChaCha20Poly1305Encrypt(
byte* keyPtr,
int keyLength,
byte* noncePtr,
int nonceLength,
byte* plaintextPtr,
int plaintextLength,
byte* ciphertextPtr,
int ciphertextLength,
byte* tagPtr,
int tagLength,
byte* aadPtr,
int aadLength);

[LibraryImport(Libraries.AppleCryptoNative)]
private static unsafe partial int AppleCryptoNative_ChaCha20Poly1305Decrypt(
byte* keyPtr,
int keyLength,
byte* noncePtr,
int nonceLength,
byte* ciphertextPtr,
int ciphertextLength,
byte* tagPtr,
int tagLength,
byte* plaintextPtr,
int plaintextLength,
byte* aadPtr,
int aadLength);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,7 @@
<Compile Include="System\Security\Cryptography\CapiHelper.DSA.Shared.cs" />
<Compile Include="System\Security\Cryptography\CapiHelper.Shared.cs" />
<Compile Include="System\Security\Cryptography\CapiHelper.Unix.cs" />
<Compile Include="System\Security\Cryptography\ChaCha20Poly1305.OpenSsl.cs" />
<Compile Include="System\Security\Cryptography\Cng.NotSupported.cs" />
<Compile Include="System\Security\Cryptography\CspKeyContainerInfo.NotSupported.cs" />
<Compile Include="System\Security\Cryptography\DESCryptoServiceProvider.Unix.cs" />
Expand Down Expand Up @@ -868,7 +869,6 @@
Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.Cipher.cs" />
<Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeEvpCipherCtxHandle.Unix.cs"
Link="Common\Microsoft\Win32\SafeHandles\SafeEvpCipherCtxHandle.Unix.cs" />
<Compile Include="System\Security\Cryptography\ChaCha20Poly1305.OpenSsl.cs" />
<Compile Include="System\Security\Cryptography\AesCcm.OpenSsl.cs" />
<Compile Include="System\Security\Cryptography\AesGcm.OpenSsl.cs" />
</ItemGroup>
Expand Down Expand Up @@ -1257,6 +1257,8 @@
Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Rsa.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs"
Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs" />
<Compile Include="$(CommonPath)Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Aead.cs"
Link="Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Aead.cs" />
<Compile Include="$(CommonPath)Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Keychain.macOS.cs"
Link="Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Keychain.macOS.cs" />
<Compile Include="$(CommonPath)Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Pbkdf2.cs"
Expand Down Expand Up @@ -1289,6 +1291,7 @@
Link="Common\System\Security\Cryptography\RSASecurityTransforms.macOS.cs" />
<Compile Include="$(CommonPath)System\Security\Cryptography\RSAOpenSsl.cs"
Link="Common\System\Security\Cryptography\RSAOpenSsl.cs" />
<Compile Include="System\Security\Cryptography\ChaCha20Poly1305.macOS.cs" />
<Compile Include="System\Security\Cryptography\DSA.Create.SecurityTransforms.cs" />
<Compile Include="System\Security\Cryptography\DSACryptoServiceProvider.Unix.cs" />
<Compile Include="System\Security\Cryptography\DSAOpenSsl.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

namespace System.Security.Cryptography
{
public sealed partial class ChaCha20Poly1305
{
// CryptoKit added ChaCha20Poly1305 in macOS 10.15, which is our minimum target for macOS.
public static bool IsSupported => true;
private byte[]? _key;

[MemberNotNull(nameof(_key))]
private void ImportKey(ReadOnlySpan<byte> key)
{
// We should only be calling this in the constructor, so there shouldn't be a previous key.
Debug.Assert(_key is null);

// Pin the array on the POH so that the GC doesn't move it around to allow zeroing to be more effective.
_key = GC.AllocateArray<byte>(key.Length, pinned: true);
key.CopyTo(_key);
}

private void EncryptCore(
ReadOnlySpan<byte> nonce,
ReadOnlySpan<byte> plaintext,
Span<byte> ciphertext,
Span<byte> tag,
ReadOnlySpan<byte> associatedData = default)
{
CheckDisposed();
Interop.AppleCrypto.ChaCha20Poly1305Encrypt(
_key,
nonce,
plaintext,
ciphertext,
tag,
associatedData);
}

private void DecryptCore(
ReadOnlySpan<byte> nonce,
ReadOnlySpan<byte> ciphertext,
ReadOnlySpan<byte> tag,
Span<byte> plaintext,
ReadOnlySpan<byte> associatedData = default)
{
CheckDisposed();
Interop.AppleCrypto.ChaCha20Poly1305Decrypt(
_key,
nonce,
ciphertext,
tag,
plaintext,
associatedData);
}

public void Dispose()
{
CryptographicOperations.ZeroMemory(_key);
_key = null;
}

[MemberNotNull(nameof(_key))]
private void CheckDisposed()
{
ObjectDisposedException.ThrowIf(_key is null, this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -457,8 +457,12 @@ public static void CheckIsSupported()
// OpenSSL is present, and a high enough version,
// but the distro build options turned off ChaCha/Poly.
}
else if (PlatformDetection.OpenSslPresentOnSystem &&
(PlatformDetection.IsOSX || PlatformDetection.IsOpenSslSupported))
else if (PlatformDetection.IsOSX)
{
// CryptoKit is supported on macOS 10.15+, which is our minimum target.
expectedIsSupported = true;
}
else if (PlatformDetection.OpenSslPresentOnSystem && PlatformDetection.IsOpenSslSupported)
{
const int OpenSslChaChaMinimumVersion = 0x1_01_00_00_F; //major_minor_fix_patch_status
expectedIsSupported = SafeEvpPKeyHandle.OpenSslVersion >= OpenSslChaChaMinimumVersion;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVO
else()
set(NATIVECRYPTO_SOURCES
${NATIVECRYPTO_SOURCES}
pal_swiftbindings.o
pal_keychain_macos.c
pal_keyderivation_macos.c
pal_seckey_macos.c
Expand All @@ -38,6 +39,24 @@ else()
)
endif()

# As of CMake 3.20.2 support for Swift only works with the Ninja and XCode
# generators so we cannot rely on it. Even with the Ninja generator it doesn't
# work in combination with other languages within the same library.
if (NOT SWIFT_COMPILER_TARGET AND CLR_CMAKE_TARGET_OSX)
set(SWIFT_PLATFORM "macosx")
set(SWIFT_PLATFORM_SUFFIX "")
set(SWIFT_DEPLOYMENT_TARGET ${CMAKE_OSX_DEPLOYMENT_TARGET})
set(SWIFT_COMPILER_TARGET "${CMAKE_OSX_ARCHITECTURES}-apple-${SWIFT_PLATFORM}${SWIFT_DEPLOYMENT_TARGET}${SWIFT_PLATFORM_SUFFIX}")
endif()

add_custom_command(
OUTPUT pal_swiftbindings.o
COMMAND xcrun swiftc -emit-object -static -parse-as-library -runtime-compatibility-version none -sdk ${CMAKE_OSX_SYSROOT} -target ${SWIFT_COMPILER_TARGET} ${CMAKE_CURRENT_SOURCE_DIR}/pal_swiftbindings.swift -o pal_swiftbindings.o
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/pal_swiftbindings.swift
COMMENT "Compiling Swift file pal_swiftbindings.swift"
)
set_source_files_properties(pal_swiftbindings.o PROPERTIES EXTERNAL_OBJECT true GENERATED true)

if (CLR_CMAKE_TARGET_MACCATALYST)
add_definitions(-DTARGET_MACCATALYST)
endif()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "pal_seckey_macos.h"
#include "pal_signverify.h"
#include "pal_ssl.h"
#include "pal_swiftbindings.h"
#include "pal_symmetric.h"
#include "pal_trust_macos.h"
#include "pal_x509.h"
Expand All @@ -25,6 +26,8 @@

static const Entry s_cryptoAppleNative[] =
{
DllImportEntry(AppleCryptoNative_ChaCha20Poly1305Encrypt)
DllImportEntry(AppleCryptoNative_ChaCha20Poly1305Decrypt)
DllImportEntry(AppleCryptoNative_DigestFree)
DllImportEntry(AppleCryptoNative_DigestCreate)
DllImportEntry(AppleCryptoNative_DigestUpdate)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,10 @@ macro(append_extra_cryptography_apple_libs NativeLibsExtra)
find_library(SECURITY_LIBRARY Security)

list(APPEND ${NativeLibsExtra} ${COREFOUNDATION_LIBRARY} ${SECURITY_LIBRARY})

if (CLR_CMAKE_TARGET_OSX)
find_library(CRYPTOKIT_LIBRARY CryptoKit)

list(APPEND ${NativeLibsExtra} ${CRYPTOKIT_LIBRARY} -L/usr/lib/swift -lobjc -lswiftCore -lswiftFoundation)
endif()
endmacro()
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#pragma once

#include "pal_types.h"
#include "pal_compiler.h"

PALEXPORT int32_t AppleCryptoNative_ChaCha20Poly1305Encrypt(
uint8_t* keyPtr,
int32_t keyLength,
uint8_t* noncePtr,
int32_t nonceLength,
uint8_t* plaintextPtr,
int32_t plaintextLength,
uint8_t* ciphertextBuffer,
int32_t ciphertextBufferLength,
uint8_t* tagBuffer,
int32_t tagBufferLength,
uint8_t* aadPtr,
int32_t aadLength);

PALEXPORT int32_t AppleCryptoNative_ChaCha20Poly1305Decrypt(
uint8_t* keyPtr,
int32_t keyLength,
uint8_t* noncePtr,
int32_t nonceLength,
uint8_t* ciphertextPtr,
int32_t ciphertextLength,
uint8_t* tagPtr,
int32_t tagLength,
uint8_t* plaintextBuffer,
int32_t plaintextBufferLength,
uint8_t* aadPtr,
int32_t aadLength);
Loading

0 comments on commit 72ac50c

Please sign in to comment.