Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion Sources/CryptoExtras/RSA/RSA.swift
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,7 @@ extension _RSA.Encryption {
@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, macCatalyst 13, visionOS 1.0, *)
public struct Padding: Sendable {
internal enum Backing {
case _weakAndInsecure_pkcs1v1_5
case pkcs1_oaep(Digest)
}

Expand All @@ -663,7 +664,18 @@ extension _RSA.Encryption {
private init(_ backing: Backing) {
self.backing = backing
}


/// PKCS#1 v1.5 padding
///
/// As defined by [RFC 8017 § 7.2](https://datatracker.ietf.org/doc/html/rfc8017#section-7.2).
///
/// This padding exists only for legacy compatibility and is known to be
/// weak and insecure. This algorithm is vulnerable to chosen-ciphertext
/// attacks outlined in http://archiv.infsec.ethz.ch/education/fs08/secsem/bleichenbacher98.pdf.
///
/// When you have a choice, you should always favor OAEP over this.
public static let _WEAK_AND_INSECURE_PKCS_V1_5 = Self(._weakAndInsecure_pkcs1v1_5)

/// PKCS#1 OAEP padding
///
/// As defined by [RFC 8017 § 7.1](https://datatracker.ietf.org/doc/html/rfc8017#section-7.1).
Expand Down Expand Up @@ -711,6 +723,9 @@ extension _RSA.Encryption.PublicKey {
/// 4096|PKCS-OAEP|470 bytes
public func maximumEncryptSize(with padding: _RSA.Encryption.Padding) -> Int {
switch padding.backing {
case ._weakAndInsecure_pkcs1v1_5:
// https://www.rfc-editor.org/rfc/rfc8017#section-7.2
return (self.keySizeInBits / 8) - 11
case let .pkcs1_oaep(Digest):
// https://datatracker.ietf.org/doc/html/rfc8017#section-7.1.1
return (self.keySizeInBits / 8) - (2 * Digest.hashBitLength / 8) - 2
Expand Down
4 changes: 4 additions & 0 deletions Sources/CryptoExtras/RSA/RSA_boring.swift
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ extension BoringSSLRSAPublicKey {
CCryptoBoringSSL_EVP_PKEY_encrypt_init(ctx)

switch padding.backing {
case ._weakAndInsecure_pkcs1v1_5:
CCryptoBoringSSL_EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING)
case let .pkcs1_oaep(digest):
CCryptoBoringSSL_EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING)
switch digest {
Expand Down Expand Up @@ -883,6 +885,8 @@ extension BoringSSLRSAPrivateKey {

CCryptoBoringSSL_EVP_PKEY_decrypt_init(ctx)
switch padding.backing {
case ._weakAndInsecure_pkcs1v1_5:
CCryptoBoringSSL_EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING)
case let .pkcs1_oaep(digest):
CCryptoBoringSSL_EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING)
switch digest {
Expand Down
60 changes: 60 additions & 0 deletions Tests/CryptoExtrasTests/TestRSAEncryption.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,66 @@ final class TestRSAEncryption: XCTestCase {
XCTAssertEqual(214, pubKey2048.maximumEncryptSize(with: .PKCS1_OAEP))
XCTAssertEqual(190, pubKey2048.maximumEncryptSize(with: .PKCS1_OAEP_SHA256))
}

func testPKCS1() throws {
let pubKeyPEM = """
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAv6ElnElHGQO1BC5wsU/S01tHK8GbCnDLkxkS1259kOU250pEjOJa
ceOGFnhYzE36KXmKTrGw3o1m5vgbQz88j7/tNjymAX990I3YdWTnGQYcypp8c4TD
wHIj5Q3OHYXAC0KUHRBSKBeS+QJybrMI6SAQbFpHh9C3Q9W3WTtSAVqs8VveS4Jc
j4a3K21MNeHgNfyxwn3KTrrNs/c0yOvWlwyfxYTdWLFVVp2hn6YVQUfo7twM4BCE
Xz/6gR03NpqjVqKeyBmmMtDIy82+BzG4vd3jm02zwNvahsBy9b2NCOjq3y2ud72b
Q4bYU9/r/ccApts5BIW8ASwmYSGSmE6MzwIDAQAB
-----END RSA PUBLIC KEY-----
"""
let privKeyPEM = """
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC/oSWcSUcZA7UE
LnCxT9LTW0crwZsKcMuTGRLXbn2Q5TbnSkSM4lpx44YWeFjMTfopeYpOsbDejWbm
+BtDPzyPv+02PKYBf33Qjdh1ZOcZBhzKmnxzhMPAciPlDc4dhcALQpQdEFIoF5L5
AnJuswjpIBBsWkeH0LdD1bdZO1IBWqzxW95LglyPhrcrbUw14eA1/LHCfcpOus2z
9zTI69aXDJ/FhN1YsVVWnaGfphVBR+ju3AzgEIRfP/qBHTc2mqNWop7IGaYy0MjL
zb4HMbi93eObTbPA29qGwHL1vY0I6OrfLa53vZtDhthT3+v9xwCm2zkEhbwBLCZh
IZKYTozPAgMBAAECggEAGncL9bCdFBRR/JjZUXOfvzbc9msPmXqIcvFEi+Ijj05I
rdqw6vAb45yzmQjX4qdmRDIX6tRZg/LtYjqjsT7bg1LTVOk9V/mei537ZgMgc3FH
qqd5Ro7wZfSdhnXIoIUnR6bTQ8xMPGM9FgzDdwxcz61w9zXkqRonJUQvxTAPHEaH
SiNhRP8LUjzB0Y2ZYVXMWbs0nPPrSE+xuzjcGRX3lvz7nNOM1N4EyWto1RVJIlry
4EV8RFczo3BjPXZFbtval76AGPmurDVqBdHpDN6IBZdhz4ZX/0fq8NR2p8/6S5VZ
4Ylcth1S3HErcnG2UqT8rl/P3m9idTv4EZOg6HziyQKBgQDsmxaQCFTJnDwxSQR+
4j9WsgDpSxvCdnUtMX9w77aw3EIdcHkhnX99jTvNkt3uwGAsVsx4x7ilj1eaZOfl
soMIX1WBBx11yN4GOw173VmzC0LtaBGTh/2ollxuNoEqYxkuKLNxWxTGW0uc5TVA
0hK2c6cF4eZ5sH07aIU6HIIknQKBgQDPVkeyxhF6lvgobLxFQOChOyLVcb1EymnU
W1zF27HciA+0FuaiWTj69bKoR8d+ZIFtIzVvjo7MfoFRJvEZmDGy5+I8HhpSW6JQ
NLdaRI5RGYxbEGmmC48icknXioZJ8JOXhbVuMyT4uLaN5D1M47ZYaq75dPM83fqZ
BDc+izDdWwKBgQCJw5d0j9VGeni1va0nb/avNP/A1qG4LZ72jH6GtJysB+NbHtT4
1KqZ4PU0MlKUpGCbEIMHxEpn47l/RUec/765zkCL2ye1IBreh93HBFApJuJ2NwUc
4K66TapN5eB5XLAZp0ssMns7L4csOG00a9zHbTmP/ENlEXUpdSc1ecnxJQKBgFsJ
n2G35mTVdREK7X/bBMbGmHzv/BMAbYd4tjuKQ4Z5l6uTgqE2W/aVe2S4X7f3mXy6
QPRCvCC+Szm+x45dbTUI7CVJcnVHFvXwr7FK+NJTTXWOt1TZLngJhrLFeEFvCN83
Lnq8qjcro7yZwvDH64DXFw0hdMv9C9O0Li2gIEyRAoGBAK+C7Stfm3vViV2YfByt
MI73t2rN+t3ffnKsXZtGzWW1kxv4cueiAdeM7QwE2AaN7yKzsSMfsSXe+/r69wUR
UPB8NcGLKWE/gJuIcitQx1HCbQZ3AplRK6xhjDVXG1A5SszQVx09hhq76JVBm0sJ
DDYta1f+sEfAS750XLJ7A1h0
-----END PRIVATE KEY-----
"""
let pubKey = try _RSA.Encryption.PublicKey(pemRepresentation: pubKeyPEM)
let privKey = try _RSA.Encryption.PrivateKey(pemRepresentation: privKeyPEM)
let msgs = [
// empty
"",
// short
"467A8AFB-9165-484A-8377-B66BCACD774A",
// example text
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla rutrum odio ut sem luctus, non finibus diam congue. Suspendisse nisl enim, placerat consectetur dolor non, mattis sollicitudin augue.",
// max length
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla rutrum odio ut sem luctus, non finibus diam congue. Suspendisse nisl enim, placerat consectetur dolor non, mattis sollicitudin augue. Pellentesque a est eget enim efficitur volutpat ",
]
for msg in msgs {
let msgEnc = try pubKey.encrypt(msg.data(using: .utf8)!, padding: ._WEAK_AND_INSECURE_PKCS_V1_5)
let msgDec = String(data: try privKey.decrypt(msgEnc, padding: ._WEAK_AND_INSECURE_PKCS_V1_5), encoding: .utf8)!
XCTAssertEqual(msg, msgDec)
}
}
}

struct RSAEncryptionOAEPTestGroup: Codable {
Expand Down