Skip to content

[Discussion] Generate C# bindings for CryptoKit framework #2583

@kotlarmilos

Description

@kotlarmilos

Objective

Our goal is to generate CryptoKit APIs bindings used for encryption and decryption. We aim to replace the existing Objective-C bindings with direct calls into Swift.

Dev template

The CryptoKit framework implements enum types with inner structs. Besides the Swift primitive types, the framework depends on Data frozen struct from Foundation framework. Additionally, the implementation contains generics and optional parameters in function signatures. To implement the C# projections, we identified the following implementation phases.

Frozen structs: Utilize runtime lowering support within the runtime to project parameters as UnsafeRawBufferPointer/UnsafeMutableBufferPointer<T> and call into a Swift wrapper that calls the CryptoKit API.

import CryptoKit
import Foundation

public func AppleCryptoNative_ChaCha20Poly1305Encrypt(
    keyBuffer: UnsafeRawBufferPointer,
    nonceBuffer: UnsafeRawBufferPointer,
    plaintextBuffer: UnsafeRawBufferPointer,
    ciphertextBuffer: UnsafeMutableBufferPointer<UInt8>,
    tagBuffer: UnsafeMutableBufferPointer<UInt8>,
    aadBuffer: UnsafeRawBufferPointer
 ) -> Int32 {
    let nonce = try! ChaChaPoly.Nonce(data: nonceBuffer)
    let symmetricKey = SymmetricKey(data: keyBuffer)

    guard let result = try? ChaChaPoly.seal(plaintextBuffer, using: symmetricKey, nonce: nonce, authenticating: aadBuffer) else {
        return 0
    }

    assert(ciphertextBuffer.count >= result.ciphertext.count)
    assert(tagBuffer.count >= result.tag.count)

    result.ciphertext.copyBytes(to: ciphertextBuffer, count: result.ciphertext.count)
    result.tag.copyBytes(to: tagBuffer, count: result.tag.count)
    return 1
 }

Surface type constructors: Surface type constructors for symmetric key and nonce, making them accessible as C# types. This requires support for SwiftSelf in instance methods and SwiftError for methods that can throw errors.

    let nonce = try! ChaChaPoly.Nonce(data: nonceBuffer)
    let symmetricKey = SymmetricKey(data: keyBuffer)
    guard let result = try! ChaChaPoly.seal(plaintextBuffer, using: symmetricKey, nonce: nonce, authenticating: aadBuffer)

Implement optional and generics projections: Implement direct calls into Swift methods by adding implicit metadata parameters and protocol witness tables for generics. This includes changes from dotnet/runtime#100543.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions