O CryptoKit é o framework que os apps Swift nas plataformas da Apple usam para hash, assinaturas, acordo de chaves, AEAD e HPKE. Ele vem com o sistema operacional, então a versão dele é a do sistema; o SDK marca a P-256 como disponível a partir do iOS 13 e do macOS 10.15, e ML-KEM, ML-DSA e X-Wing a partir do iOS 26 e do macOS 26. Os fatos desta página foram conferidos no macOS 27.0.1 com Swift 6.4 em um Mac com Apple silicon, e os dois exemplos foram compilados e executados ali; o iOS não foi verificado. No Linux, a mesma API vem do swift-crypto.
Uma assinatura P-256 é um valor ECDSASignature com duas formas: rawRepresentation, o r‖s de 64 bytes usado pelo JWS (ES256) e pela WebCrypto, e derRepresentation, a forma DER que X.509, OpenSSL e Java esperam. Enviar a forma errada é um bug de interoperabilidade comum; o exemplo converte explicitamente, e o conversor DER ⇄ bruto mostra as duas. O parsing é estrito e lança erros: bytes brutos passados a init(derRepresentation:) lançam um CryptoKitASN1Error — truncatedASN1Field para a assinatura de teste da RFC 6979, embora o caso dependa dos bytes —, e DER passado a init(rawRepresentation:) lança incorrectParameterSize, enquanto isValidSignature simplesmente retorna false.
Os nonces são aleatórios — duas assinaturas de uma mesma mensagem foram diferentes, e a chave de teste da RFC 6979 não produziu o r da RFC — e o s não é normalizado: aparecem valores high-S, e uma assinatura com s substituído por n − s foi verificada. signature(for: data) calcula o hash com o hash que corresponde à curva (SHA-256, SHA-384, SHA-512), mas signature(for: digest) aceita qualquer tipo de digest: um digest SHA-256 foi assinado e verificado com uma chave P-384, e um digest SHA-512 na P-256 foi truncado para os primeiros 32 bytes, o que o Security.framework confirmou. Ao fazer o pré-hash, passe você mesmo o digest correspondente à curva.
As assinaturas Ed25519 (Curve25519.Signing) usam aleatoriedade: com a chave de teste da RFC 8032, a assinatura do CryptoKit sobre a mensagem de teste foi diferente da assinatura da RFC e da anterior do próprio CryptoKit, mas ambas foram verificadas, inclusive com o Node.js. Por isso, testes que comparam os bytes da assinatura com os vetores da RFC 8032 falham com o CryptoKit no macOS; verifique as assinaturas em vez disso. Valores de S não canônicos são rejeitados, mas o ponto identidade foi aceito como chave pública, e uma assinatura com R = identidade e S = 0 foi verificada para uma mensagem arbitrária. Rejeite você mesmo chaves de ordem pequena quando uma assinatura precisar estar vinculada a um signatário específico. As chaves Ed25519 existem apenas como 32 bytes brutos; não há forma PEM nem DER para elas.
Os tipos pós-quânticos são ML-KEM-768 e ML-KEM-1024, ML-DSA-65 e ML-DSA-87 — não há ML-KEM-512, ML-DSA-44 nem SLH-DSA — e o KEM híbrido X-Wing (XWingMLKEM768X25519), também oferecido como cipher suite do HPKE. A assinatura ML-DSA usa aleatoriedade adicional (hedged) e aceita uma string de contexto da FIPS 204, que o verificador precisa repetir. O desencapsulamento ML-KEM de um texto cifrado danificado retorna uma chave diferente em vez de lançar um erro. As chaves privadas são armazenadas apenas como sementes — 64 bytes para ML-KEM, 32 para ML-DSA — ou como a semente com uma verificação de integridade, então uma chave privada expandida exportada por outra biblioteca não pode ser importada. Experimente os esquemas na ferramenta de ML-KEM e na ferramenta de assinaturas pós-quânticas.
SecureEnclave.P256.Signing.PrivateKey() cria uma chave dentro do Secure Enclave, e, neste Mac, os tipos ML-KEM e ML-DSA sob SecureEnclave fizeram o mesmo. Esses tipos não expõem a chave privada em forma bruta, DER ou PEM — só dataRepresentation, um identificador (handle) que reabriu a chave —, enquanto a chave pública é uma P256.Signing.PublicKey ou MLDSA65.PublicKey comum. As chaves P-256 em software são exportadas como PKCS#8 (derRepresentation, pemRepresentation) e importadas de PKCS#8 e SEC1, em PEM ou DER, mas não de PKCS#8 criptografado, e o CryptoKit não oferece suporte a JWK.