Skip to content

Commit 43dbffa

Browse files
authored
Convert our CryptoKit bindings to use Swift structs at the boundary (dotnet#102583)
* Try converting our CryptoKit bindings to use more Swift types. Also refactor our cryptokit bindings to reduce duplication. * Fix build on macos * Remove target-typed new and other style changes * Don't pass down null with UnsafeBufferPointer * Call copyBytes with a pointer because everything else seems to fail some assert for some reason I can't figure out. * Make copies and use copyBytes(to: buffer) again. * Fix generic value types condition * Put SwiftError parameter first to try working around Mono register allocation bug * Comma
1 parent 35aef5c commit 43dbffa

File tree

8 files changed

+300
-255
lines changed

8 files changed

+300
-255
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Swift.Runtime
5+
{
6+
// <summary>
7+
// Represents Swift UnsafeBufferPointer in C#.
8+
// </summary>
9+
internal readonly unsafe struct UnsafeBufferPointer<T> where T : unmanaged
10+
{
11+
private readonly T* _baseAddress;
12+
private readonly nint _count;
13+
public UnsafeBufferPointer(T* baseAddress, nint count)
14+
{
15+
_baseAddress = baseAddress;
16+
_count = count;
17+
}
18+
19+
public T* BaseAddress => _baseAddress;
20+
public nint Count => _count;
21+
}
22+
23+
// <summary>
24+
// Represents Swift UnsafeMutableBufferPointer in C#.
25+
// </summary>
26+
internal readonly unsafe struct UnsafeMutableBufferPointer<T> where T : unmanaged
27+
{
28+
private readonly T* _baseAddress;
29+
private readonly nint _count;
30+
public UnsafeMutableBufferPointer(T* baseAddress, nint count)
31+
{
32+
_baseAddress = baseAddress;
33+
_count = count;
34+
}
35+
36+
public T* BaseAddress => _baseAddress;
37+
public nint Count => _count;
38+
}
39+
}

src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Aead.cs

Lines changed: 104 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,28 @@
55
using System.Diagnostics;
66
using System.Runtime.CompilerServices;
77
using System.Runtime.InteropServices;
8+
using System.Runtime.InteropServices.Swift;
89
using System.Security.Cryptography;
910
using System.Security.Cryptography.Apple;
11+
using Swift.Runtime;
1012

1113
#pragma warning disable CS3016 // Arrays as attribute arguments are not CLS Compliant
1214

1315
internal static partial class Interop
1416
{
1517
internal static partial class AppleCrypto
1618
{
19+
private static byte NullSentinel;
20+
21+
// CryptoKit doesn't do well with a null pointer for the buffer data,
22+
// so provide a sentinel pointer instead.
23+
private static ref readonly byte GetSwiftRef(ReadOnlySpan<byte> b)
24+
{
25+
return ref (b.Length == 0
26+
? ref NullSentinel
27+
: ref MemoryMarshal.GetReference(b));
28+
}
29+
1730
internal static unsafe void ChaCha20Poly1305Encrypt(
1831
ReadOnlySpan<byte> key,
1932
ReadOnlySpan<byte> nonce,
@@ -24,23 +37,22 @@ internal static unsafe void ChaCha20Poly1305Encrypt(
2437
{
2538
fixed (byte* keyPtr = key)
2639
fixed (byte* noncePtr = nonce)
27-
fixed (byte* plaintextPtr = plaintext)
28-
fixed (byte* ciphertextPtr = ciphertext)
40+
fixed (byte* plaintextPtr = &GetSwiftRef(plaintext))
41+
fixed (byte* ciphertextPtr = &GetSwiftRef(ciphertext))
2942
fixed (byte* tagPtr = tag)
30-
fixed (byte* aadPtr = aad)
43+
fixed (byte* aadPtr = &GetSwiftRef(aad))
3144
{
32-
const int Success = 1;
33-
int result = AppleCryptoNative_ChaCha20Poly1305Encrypt(
34-
keyPtr, key.Length,
35-
noncePtr, nonce.Length,
36-
plaintextPtr, plaintext.Length,
37-
ciphertextPtr, ciphertext.Length,
38-
tagPtr, tag.Length,
39-
aadPtr, aad.Length);
40-
41-
if (result != Success)
45+
AppleCryptoNative_ChaCha20Poly1305Encrypt(
46+
out SwiftError error,
47+
new UnsafeBufferPointer<byte>(keyPtr, key.Length),
48+
new UnsafeBufferPointer<byte>(noncePtr, nonce.Length),
49+
new UnsafeBufferPointer<byte>(plaintextPtr, plaintext.Length),
50+
new UnsafeMutableBufferPointer<byte>(ciphertextPtr, ciphertext.Length),
51+
new UnsafeMutableBufferPointer<byte>(tagPtr, tag.Length),
52+
new UnsafeBufferPointer<byte>(aadPtr, aad.Length));
53+
54+
if (error.Value != null)
4255
{
43-
Debug.Assert(result == 0);
4456
CryptographicOperations.ZeroMemory(ciphertext);
4557
CryptographicOperations.ZeroMemory(tag);
4658
throw new CryptographicException();
@@ -58,32 +70,30 @@ internal static unsafe void ChaCha20Poly1305Decrypt(
5870
{
5971
fixed (byte* keyPtr = key)
6072
fixed (byte* noncePtr = nonce)
61-
fixed (byte* ciphertextPtr = ciphertext)
73+
fixed (byte* ciphertextPtr = &GetSwiftRef(ciphertext))
6274
fixed (byte* tagPtr = tag)
63-
fixed (byte* plaintextPtr = plaintext)
64-
fixed (byte* aadPtr = aad)
75+
fixed (byte* plaintextPtr = &GetSwiftRef(plaintext))
76+
fixed (byte* aadPtr = &GetSwiftRef(aad))
6577
{
66-
const int Success = 1;
67-
const int AuthTagMismatch = -1;
68-
int result = AppleCryptoNative_ChaCha20Poly1305Decrypt(
69-
keyPtr, key.Length,
70-
noncePtr, nonce.Length,
71-
ciphertextPtr, ciphertext.Length,
72-
tagPtr, tag.Length,
73-
plaintextPtr, plaintext.Length,
74-
aadPtr, aad.Length);
75-
76-
if (result != Success)
78+
AppleCryptoNative_ChaCha20Poly1305Decrypt(
79+
out SwiftError error,
80+
new UnsafeBufferPointer<byte>(keyPtr, key.Length),
81+
new UnsafeBufferPointer<byte>(noncePtr, nonce.Length),
82+
new UnsafeBufferPointer<byte>(ciphertextPtr, ciphertext.Length),
83+
new UnsafeBufferPointer<byte>(tagPtr, tag.Length),
84+
new UnsafeMutableBufferPointer<byte>(plaintextPtr, plaintext.Length),
85+
new UnsafeBufferPointer<byte>(aadPtr, aad.Length));
86+
87+
if (error.Value != null)
7788
{
7889
CryptographicOperations.ZeroMemory(plaintext);
7990

80-
if (result == AuthTagMismatch)
91+
if (AppleCryptoNative_IsAuthenticationFailure(error.Value))
8192
{
8293
throw new AuthenticationTagMismatchException();
8394
}
8495
else
8596
{
86-
Debug.Assert(result == 0);
8797
throw new CryptographicException();
8898
}
8999
}
@@ -100,23 +110,22 @@ internal static unsafe void AesGcmEncrypt(
100110
{
101111
fixed (byte* keyPtr = key)
102112
fixed (byte* noncePtr = nonce)
103-
fixed (byte* plaintextPtr = plaintext)
104-
fixed (byte* ciphertextPtr = ciphertext)
113+
fixed (byte* plaintextPtr = &GetSwiftRef(plaintext))
114+
fixed (byte* ciphertextPtr = &GetSwiftRef(ciphertext))
105115
fixed (byte* tagPtr = tag)
106-
fixed (byte* aadPtr = aad)
116+
fixed (byte* aadPtr = &GetSwiftRef(aad))
107117
{
108-
const int Success = 1;
109-
int result = AppleCryptoNative_AesGcmEncrypt(
110-
keyPtr, key.Length,
111-
noncePtr, nonce.Length,
112-
plaintextPtr, plaintext.Length,
113-
ciphertextPtr, ciphertext.Length,
114-
tagPtr, tag.Length,
115-
aadPtr, aad.Length);
116-
117-
if (result != Success)
118+
AppleCryptoNative_AesGcmEncrypt(
119+
out SwiftError error,
120+
new UnsafeBufferPointer<byte>(keyPtr, key.Length),
121+
new UnsafeBufferPointer<byte>(noncePtr, nonce.Length),
122+
new UnsafeBufferPointer<byte>(plaintextPtr, plaintext.Length),
123+
new UnsafeMutableBufferPointer<byte>(ciphertextPtr, ciphertext.Length),
124+
new UnsafeMutableBufferPointer<byte>(tagPtr, tag.Length),
125+
new UnsafeBufferPointer<byte>(aadPtr, aad.Length));
126+
127+
if (error.Value != null)
118128
{
119-
Debug.Assert(result == 0);
120129
CryptographicOperations.ZeroMemory(ciphertext);
121130
CryptographicOperations.ZeroMemory(tag);
122131
throw new CryptographicException();
@@ -134,32 +143,30 @@ internal static unsafe void AesGcmDecrypt(
134143
{
135144
fixed (byte* keyPtr = key)
136145
fixed (byte* noncePtr = nonce)
137-
fixed (byte* ciphertextPtr = ciphertext)
146+
fixed (byte* ciphertextPtr = &GetSwiftRef(ciphertext))
138147
fixed (byte* tagPtr = tag)
139-
fixed (byte* plaintextPtr = plaintext)
140-
fixed (byte* aadPtr = aad)
148+
fixed (byte* plaintextPtr = &GetSwiftRef(plaintext))
149+
fixed (byte* aadPtr = &GetSwiftRef(aad))
141150
{
142-
const int Success = 1;
143-
const int AuthTagMismatch = -1;
144-
int result = AppleCryptoNative_AesGcmDecrypt(
145-
keyPtr, key.Length,
146-
noncePtr, nonce.Length,
147-
ciphertextPtr, ciphertext.Length,
148-
tagPtr, tag.Length,
149-
plaintextPtr, plaintext.Length,
150-
aadPtr, aad.Length);
151-
152-
if (result != Success)
151+
AppleCryptoNative_AesGcmDecrypt(
152+
out SwiftError error,
153+
new UnsafeBufferPointer<byte>(keyPtr, key.Length),
154+
new UnsafeBufferPointer<byte>(noncePtr, nonce.Length),
155+
new UnsafeBufferPointer<byte>(ciphertextPtr, ciphertext.Length),
156+
new UnsafeBufferPointer<byte>(tagPtr, tag.Length),
157+
new UnsafeMutableBufferPointer<byte>(plaintextPtr, plaintext.Length),
158+
new UnsafeBufferPointer<byte>(aadPtr, aad.Length));
159+
160+
if (error.Value != null)
153161
{
154162
CryptographicOperations.ZeroMemory(plaintext);
155163

156-
if (result == AuthTagMismatch)
164+
if (AppleCryptoNative_IsAuthenticationFailure(error.Value))
157165
{
158166
throw new AuthenticationTagMismatchException();
159167
}
160168
else
161169
{
162-
Debug.Assert(result == 0);
163170
throw new CryptographicException();
164171
}
165172
}
@@ -168,66 +175,51 @@ internal static unsafe void AesGcmDecrypt(
168175

169176
[LibraryImport(Libraries.AppleCryptoNative)]
170177
[UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])]
171-
private static unsafe partial int AppleCryptoNative_ChaCha20Poly1305Encrypt(
172-
byte* keyPtr,
173-
int keyLength,
174-
byte* noncePtr,
175-
int nonceLength,
176-
byte* plaintextPtr,
177-
int plaintextLength,
178-
byte* ciphertextPtr,
179-
int ciphertextLength,
180-
byte* tagPtr,
181-
int tagLength,
182-
byte* aadPtr,
183-
int aadLength);
178+
private static unsafe partial void AppleCryptoNative_ChaCha20Poly1305Encrypt(
179+
out SwiftError error,
180+
UnsafeBufferPointer<byte> key,
181+
UnsafeBufferPointer<byte> nonce,
182+
UnsafeBufferPointer<byte> plaintext,
183+
UnsafeMutableBufferPointer<byte> ciphertext,
184+
UnsafeMutableBufferPointer<byte> tag,
185+
UnsafeBufferPointer<byte> aad);
184186

185187
[LibraryImport(Libraries.AppleCryptoNative)]
186188
[UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])]
187-
private static unsafe partial int AppleCryptoNative_ChaCha20Poly1305Decrypt(
188-
byte* keyPtr,
189-
int keyLength,
190-
byte* noncePtr,
191-
int nonceLength,
192-
byte* ciphertextPtr,
193-
int ciphertextLength,
194-
byte* tagPtr,
195-
int tagLength,
196-
byte* plaintextPtr,
197-
int plaintextLength,
198-
byte* aadPtr,
199-
int aadLength);
189+
private static unsafe partial void AppleCryptoNative_ChaCha20Poly1305Decrypt(
190+
out SwiftError error,
191+
UnsafeBufferPointer<byte> key,
192+
UnsafeBufferPointer<byte> nonce,
193+
UnsafeBufferPointer<byte> ciphertext,
194+
UnsafeBufferPointer<byte> tag,
195+
UnsafeMutableBufferPointer<byte> plaintext,
196+
UnsafeBufferPointer<byte> aad);
200197

201198
[LibraryImport(Libraries.AppleCryptoNative)]
202199
[UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])]
203-
private static unsafe partial int AppleCryptoNative_AesGcmEncrypt(
204-
byte* keyPtr,
205-
int keyLength,
206-
byte* noncePtr,
207-
int nonceLength,
208-
byte* plaintextPtr,
209-
int plaintextLength,
210-
byte* ciphertextPtr,
211-
int ciphertextLength,
212-
byte* tagPtr,
213-
int tagLength,
214-
byte* aadPtr,
215-
int aadLength);
200+
private static unsafe partial void AppleCryptoNative_AesGcmEncrypt(
201+
out SwiftError error,
202+
UnsafeBufferPointer<byte> key,
203+
UnsafeBufferPointer<byte> nonce,
204+
UnsafeBufferPointer<byte> plaintext,
205+
UnsafeMutableBufferPointer<byte> ciphertext,
206+
UnsafeMutableBufferPointer<byte> tag,
207+
UnsafeBufferPointer<byte> aad);
216208

217209
[LibraryImport(Libraries.AppleCryptoNative)]
218210
[UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])]
219-
private static unsafe partial int AppleCryptoNative_AesGcmDecrypt(
220-
byte* keyPtr,
221-
int keyLength,
222-
byte* noncePtr,
223-
int nonceLength,
224-
byte* ciphertextPtr,
225-
int ciphertextLength,
226-
byte* tagPtr,
227-
int tagLength,
228-
byte* plaintextPtr,
229-
int plaintextLength,
230-
byte* aadPtr,
231-
int aadLength);
211+
private static unsafe partial void AppleCryptoNative_AesGcmDecrypt(
212+
out SwiftError error,
213+
UnsafeBufferPointer<byte> key,
214+
UnsafeBufferPointer<byte> nonce,
215+
UnsafeBufferPointer<byte> ciphertext,
216+
UnsafeBufferPointer<byte> tag,
217+
UnsafeMutableBufferPointer<byte> plaintext,
218+
UnsafeBufferPointer<byte> aad);
219+
220+
[LibraryImport(Libraries.AppleCryptoNative)]
221+
[UnmanagedCallConv(CallConvs = new[] { typeof(CallConvSwift) })]
222+
[return: MarshalAs(UnmanagedType.U1)]
223+
private static unsafe partial bool AppleCryptoNative_IsAuthenticationFailure(void* error);
232224
}
233225
}

src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,8 @@
12101210
Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Rsa.cs" />
12111211
<Compile Include="$(CommonPath)Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs"
12121212
Link="Common\Interop\Unix\System.Security.Cryptography.Native\Interop.OpenSslVersion.cs" />
1213+
<Compile Include="$(CommonPath)Interop\OSX\Swift.Runtime\UnsafeBufferPointer.cs"
1214+
Link="Common\Interop\OSX\Swift.Runtime\UnsafeBufferPointer.cs" />
12131215
<Compile Include="$(CommonPath)Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Aead.cs"
12141216
Link="Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Aead.cs" />
12151217
<Compile Include="$(CommonPath)Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.Keychain.macOS.cs"

src/mono/mono/metadata/marshal.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6818,9 +6818,11 @@ mono_marshal_get_swift_physical_lowering (MonoType *type, gboolean native_layout
68186818
}
68196819

68206820
// Non-value types are illegal at the interop boundary.
6821-
if (type->type == MONO_TYPE_GENERICINST && !mono_type_generic_inst_is_valuetype (type)) {
6822-
lowering.by_reference = TRUE;
6823-
return lowering;
6821+
if (type->type == MONO_TYPE_GENERICINST) {
6822+
if (!mono_type_generic_inst_is_valuetype (type)) {
6823+
lowering.by_reference = TRUE;
6824+
return lowering;
6825+
}
68246826
} else if (type->type != MONO_TYPE_VALUETYPE && !mono_type_is_primitive(type)) {
68256827
lowering.by_reference = TRUE;
68266828
return lowering;

src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ endif()
5151

5252
add_custom_command(
5353
OUTPUT pal_swiftbindings.o
54-
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
54+
COMMAND xcrun swiftc -emit-object -static -parse-as-library -enable-library-evolution -g -runtime-compatibility-version none -sdk ${CMAKE_OSX_SYSROOT} -target ${SWIFT_COMPILER_TARGET} ${CMAKE_CURRENT_SOURCE_DIR}/pal_swiftbindings.swift -o pal_swiftbindings.o
5555
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/pal_swiftbindings.swift
5656
COMMENT "Compiling Swift file pal_swiftbindings.swift"
5757
)

src/native/libs/System.Security.Cryptography.Native.Apple/entrypoints.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ static const Entry s_cryptoAppleNative[] =
4848
DllImportEntry(AppleCryptoNative_HmacFinal)
4949
DllImportEntry(AppleCryptoNative_HmacCurrent)
5050
DllImportEntry(AppleCryptoNative_HmacOneShot)
51+
DllImportEntry(AppleCryptoNative_IsAuthenticationFailure)
5152
DllImportEntry(AppleCryptoNative_SecKeychainItemCopyKeychain)
5253
DllImportEntry(AppleCryptoNative_SecKeychainCopyDefault)
5354
DllImportEntry(AppleCryptoNative_SecKeychainCreate)

src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ EXTERN_C void* AppleCryptoNative_ChaCha20Poly1305Encrypt;
1010
EXTERN_C void* AppleCryptoNative_ChaCha20Poly1305Decrypt;
1111
EXTERN_C void* AppleCryptoNative_AesGcmEncrypt;
1212
EXTERN_C void* AppleCryptoNative_AesGcmDecrypt;
13+
EXTERN_C void* AppleCryptoNative_IsAuthenticationFailure;

0 commit comments

Comments
 (0)