Repository: krzyzanowskim/CryptoSwift Branch: main Commit: a2acb6155f49 Files: 203 Total size: 1.2 MB Directory structure: gitextract_0h7qiraw/ ├── .editorconfig ├── .github/ │ ├── CODEOWNERS │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ └── bug_report.md │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows/ │ ├── android.yml │ ├── linux.yml │ └── macos.yml ├── .gitignore ├── .mailmap ├── .spi.yml ├── .swiftformat ├── CHANGELOG ├── CNAME ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CONTRIBUTORS.txt ├── CryptoSwift-TestHostApp/ │ ├── AppDelegate.swift │ └── Info.plist ├── CryptoSwift.podspec ├── CryptoSwift.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ ├── CryptoSwift.xcscmblueprint │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata/ │ ├── IDETemplateMacros.plist │ └── xcschemes/ │ ├── CryptoSwift-TestHostApp.xcscheme │ ├── CryptoSwift.xcscheme │ ├── Tests.xcscheme │ ├── TestsPerformance-Mac.xcscheme │ └── TestsPerformance-iOS.xcscheme ├── Info.plist ├── LICENSE ├── Makefile ├── Package.swift ├── README.md ├── Sources/ │ ├── CryptoSwift/ │ │ ├── AEAD/ │ │ │ ├── AEAD.swift │ │ │ ├── AEADChaCha20Poly1305.swift │ │ │ └── AEADXChaCha20Poly1305.swift │ │ ├── AES.Cryptors.swift │ │ ├── AES.swift │ │ ├── ASN1/ │ │ │ ├── ASN1.swift │ │ │ ├── ASN1Decoder.swift │ │ │ ├── ASN1Encoder.swift │ │ │ └── ASN1Scanner.swift │ │ ├── Array+Extension.swift │ │ ├── Authenticator.swift │ │ ├── BatchedCollection.swift │ │ ├── Bit.swift │ │ ├── BlockCipher.swift │ │ ├── BlockDecryptor.swift │ │ ├── BlockEncryptor.swift │ │ ├── BlockMode/ │ │ │ ├── BlockMode.swift │ │ │ ├── BlockModeOptions.swift │ │ │ ├── CBC.swift │ │ │ ├── CCM.swift │ │ │ ├── CFB.swift │ │ │ ├── CTR.swift │ │ │ ├── CipherModeWorker.swift │ │ │ ├── ECB.swift │ │ │ ├── GCM.swift │ │ │ ├── OCB.swift │ │ │ ├── OFB.swift │ │ │ └── PCBC.swift │ │ ├── Blowfish.swift │ │ ├── CBCMAC.swift │ │ ├── CMAC.swift │ │ ├── CS_BigInt/ │ │ │ ├── Addition.swift │ │ │ ├── BigInt.swift │ │ │ ├── BigUInt.swift │ │ │ ├── BitwiseOps.swift │ │ │ ├── CS.swift │ │ │ ├── Codable.swift │ │ │ ├── Comparable.swift │ │ │ ├── DataConversion.swift │ │ │ ├── Division.swift │ │ │ ├── Exponentiation.swift │ │ │ ├── FloatingPointConversion.swift │ │ │ ├── GCD.swift │ │ │ ├── Hashable.swift │ │ │ ├── IntegerConversion.swift │ │ │ ├── Multiplication.swift │ │ │ ├── PrimeTest.swift │ │ │ ├── Random.swift │ │ │ ├── Shifts.swift │ │ │ ├── SquareRoot.swift │ │ │ ├── Strideable.swift │ │ │ ├── StringConversion.swift │ │ │ ├── Subtraction.swift │ │ │ └── WordsAndBits.swift │ │ ├── ChaCha20.swift │ │ ├── Checksum.swift │ │ ├── Cipher.swift │ │ ├── Collection+Extension.swift │ │ ├── CompactMap.swift │ │ ├── Cryptor.swift │ │ ├── Cryptors.swift │ │ ├── Digest.swift │ │ ├── DigestType.swift │ │ ├── Foundation/ │ │ │ ├── AES+Foundation.swift │ │ │ ├── Array+Foundation.swift │ │ │ ├── Blowfish+Foundation.swift │ │ │ ├── ChaCha20+Foundation.swift │ │ │ ├── Data+Extension.swift │ │ │ ├── HMAC+Foundation.swift │ │ │ ├── Rabbit+Foundation.swift │ │ │ ├── String+FoundationExtension.swift │ │ │ ├── Utils+Foundation.swift │ │ │ └── XChaCha20+Foundation.swift │ │ ├── Generics.swift │ │ ├── HKDF.swift │ │ ├── HMAC.swift │ │ ├── ISO10126Padding.swift │ │ ├── ISO78164Padding.swift │ │ ├── Int+Extension.swift │ │ ├── MD5.swift │ │ ├── NoPadding.swift │ │ ├── Operators.swift │ │ ├── PEM/ │ │ │ └── DER.swift │ │ ├── PKCS/ │ │ │ ├── PBKDF1.swift │ │ │ ├── PBKDF2.swift │ │ │ ├── PKCS1v15.swift │ │ │ ├── PKCS5.swift │ │ │ ├── PKCS7.swift │ │ │ └── PKCS7Padding.swift │ │ ├── Padding.swift │ │ ├── Poly1305.swift │ │ ├── PrivacyInfo.xcprivacy │ │ ├── RSA/ │ │ │ ├── RSA+Cipher.swift │ │ │ ├── RSA+Signature.swift │ │ │ └── RSA.swift │ │ ├── Rabbit.swift │ │ ├── SHA1.swift │ │ ├── SHA2.swift │ │ ├── SHA3.swift │ │ ├── Scrypt.swift │ │ ├── SecureBytes.swift │ │ ├── Signature.swift │ │ ├── StreamDecryptor.swift │ │ ├── StreamEncryptor.swift │ │ ├── String+Extension.swift │ │ ├── UInt128.swift │ │ ├── UInt16+Extension.swift │ │ ├── UInt32+Extension.swift │ │ ├── UInt64+Extension.swift │ │ ├── UInt8+Extension.swift │ │ ├── Updatable.swift │ │ ├── Utils.swift │ │ ├── XChaCha20.swift │ │ └── ZeroPadding.swift │ └── CryptoSwift.h ├── Tests/ │ ├── CryptoSwiftTests/ │ │ ├── AESCCMTests.swift │ │ ├── AESOCBTests.swift │ │ ├── AESTests.swift │ │ ├── AESTestsPerf.swift │ │ ├── ASN1Tests.swift │ │ ├── Access.swift │ │ ├── BlowfishTests.swift │ │ ├── Bridging.h │ │ ├── CBCMacTests.swift │ │ ├── CMACTests.swift │ │ ├── ChaCha20Poly1305Tests.swift │ │ ├── ChaCha20Tests.swift │ │ ├── ChaCha20TestsPerf.swift │ │ ├── DigestTests.swift │ │ ├── DigestTestsPerf.swift │ │ ├── Error+Extension.swift │ │ ├── ExtensionsTest.swift │ │ ├── ExtensionsTestPerf.swift │ │ ├── HKDFTests.swift │ │ ├── HMACTests.swift │ │ ├── PBKDF.swift │ │ ├── PBKDFPerf.swift │ │ ├── PaddingTests.swift │ │ ├── Poly1305Tests.swift │ │ ├── RSASecKeyTests.swift │ │ ├── RSATests.swift │ │ ├── RabbitTests.swift │ │ ├── RabbitTestsPerf.swift │ │ ├── SHATestsPerf.swift │ │ ├── ScryptTests.swift │ │ ├── ScryptTestsPerf.swift │ │ ├── SignatureVerificationTests.swift │ │ ├── XCTestManifests.swift │ │ ├── XChaCha20Poly1305Tests.swift │ │ └── XChaCha20Tests.swift │ ├── LinuxMain.swift │ └── TestsPerformance/ │ └── XCTestManifests.swift ├── _config.yml ├── config/ │ ├── CryptoSwift-Debug.xcconfig │ ├── CryptoSwift-Release.xcconfig │ ├── CryptoSwift-Shared.xcconfig │ ├── CryptoSwift-Test.xcconfig │ ├── CryptoSwift-TestHostApp-Shared.xcconfig │ ├── CryptoSwift-TestHostApp-Test.xcconfig │ ├── Project-Debug.xcconfig │ ├── Project-Release.xcconfig │ ├── Project-Shared.xcconfig │ ├── Tests-Shared.xcconfig │ └── Tests-Test.xcconfig └── scripts/ ├── build-framework.sh ├── generate-contributors-list.sh └── swiftformat.sh ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ [*] end_of_line = lf insert_final_newline = true [*.swift] charset = utf-8 indent_style = space indent_size = 2 [Makefile] indent_style = tab ================================================ FILE: .github/CODEOWNERS ================================================ * @krzyzanowskim ================================================ FILE: .github/FUNDING.yml ================================================ github: [krzyzanowskim, NathanFallet] ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve --- **Describe the bug** **Reproduce** Steps to reproduce: 1. ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ Fixes # Checklist: - [ ] Correct file headers (see CONTRIBUTING.md). - [ ] Formatted with [SwiftFormat](https://github.com/nicklockwood/SwiftFormat). - [ ] Tests added. Changes proposed in this pull request: - ================================================ FILE: .github/workflows/android.yml ================================================ name: Android on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Run tests uses: skiptools/swift-android-action@v2 ================================================ FILE: .github/workflows/linux.yml ================================================ name: Linux on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Swift Package Build run: swift build -v - name: Run tests run: swift test -c release -Xswiftc -enable-testing -Xswiftc -DCI -Xswiftc -Xfrontend -Xswiftc -solver-memory-threshold -Xswiftc -Xfrontend -Xswiftc 999999999 ================================================ FILE: .github/workflows/macos.yml ================================================ name: macOS on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: macos-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Select Xcode Version uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: latest-stable - name: Swift Package Build run: swift build -v - name: Run tests run: swift test -c release -Xswiftc -enable-testing -Xswiftc -DCI -Xswiftc -Xfrontend -Xswiftc -solver-memory-threshold -Xswiftc -Xfrontend -Xswiftc 999999999 ================================================ FILE: .gitignore ================================================ ### Xcode ### .build/ build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.xcuserstate timeline.xctimeline .swiftpm/xcode Package.resolved CryptoSwift.xcframework /Framework .DS_Store Carthage/Build .idea .vscode ================================================ FILE: .mailmap ================================================ Marcin Krzyzanowski <758033+krzyzanowskim@users.noreply.github.com> Marcin Krzyzanowski Marcin Krzyzanowski Marcin Krzyzanowski Luis Reisewitz Nathan Fallet ================================================ FILE: .spi.yml ================================================ version: 1 builder: configs: - documentation_targets: [CryptoSwift] ================================================ FILE: .swiftformat ================================================ --exclude .build, Carthage, DerivedData, .git, Tests/LinuxMain.swift, Tests/CryptoSwiftTests/XCTestManifests.swift, Tests/TestsPerformance/XCTestManifests.swift --swiftversion 5.0 --allman false --commas always --comments indent --elseposition same-line --empty void --exponentcase lowercase --exponentgrouping disabled --fractiongrouping disabled --header ignore --octalgrouping 4,8 --decimalgrouping 3,6 --binarygrouping 4,8 --hexgrouping ignore --hexliteralcase lowercase --ifdef indent --indent 2 --indentcase true --importgrouping testable-bottom --linebreaks lf --operatorfunc spaced --patternlet inline --ranges no-space --self insert --semicolons inline --stripunusedargs closure-only --trimwhitespace always --wraparguments preserve --wrapcollections before-first # rules --rules indent, braces, isEmpty, redundantBreak, blankLinesAroundMark, blankLinesAtEndOfScope, blankLinesBetweenScopes, consecutiveBlankLines, consecutiveSpaces, duplicateImports, elseOnSameLine, leadingDelimiters, redundantBreak, redundantExtensionACL, redundantFileprivate, redundantGet, redundantInit, redundantLet, redundantNilInit, redundantObjc, redundantParens, redundantPattern, redundantRawValues, redundantReturn, redundantSelf, redundantVoidReturnType, semicolons, sortedImports, spaceAroundBraces, spaceAroundBrackets, spaceAroundComments, spaceAroundGenerics, spaceAroundOperators, spaceAroundParens, spaceInsideBraces, spaceInsideBrackets, specifiers, strongOutlets, strongifiedSelf, todos, void, wrapArguments, yodaConditions, trailingSpace ================================================ FILE: CHANGELOG ================================================ 1.9.0 - Renamed bytes to byteArray in Data extension to avoid conflict with Swift 6.2 by @mluisbrown in #1076 and #1077 1.8.5 - Update README.md by @donatik27 in #1059 - Add Android support by @marcprux in #1065 - chore: fix some typos in comment by @sunxunle in #1068 - fix: typos in documentation files by @vtjl10 in #1066 - fix: typos in documentation files by @kilavvy in #1071 - docs: fix typos by @RekCuy63 in #1072 - fix: externalRepresentation condition to validate if key is private should be d not prime by @beatt83 in #1060 1.8.4 - Docs fix spelling issues by @nnsW3 in #1053 - chore: fix some comments by @dropbigfish in #1050 - docs fix spelling issues by @Guayaba221 in #1056 - Support for Static Linux SDK Based on Musl Instead of Glibc by @AnneBlair in #1058 - Use .sha2(.sha256) for PBKDF2 in readme by @sjudd in #1061 1.8.3 - Remove whitespace from the filename to please bezel build system - minors 1.8.2 - Enable VisionOS as supported platform for Xcode project and SwiftPM package - Tweak CocoaPods setup for privacy manifest 1.8.1 - Update publicKeyDER to support exponent of any byte length - Add SHA3 variants for RSA signature verification - Throw error on unsupported calls, rather than call fatalError - Update PKCS7 padding logic - Add SDK Privacy Manifest - PrivacyInfo.xcprivacy 1.8.0 - Add XChaCha20 and XChaCha20-Poly1305 (@zssz) 1.7.2 - Validate RSA input values - Minor updates 1.7.1 - Address Swift 5.8 warnings 1.7.0 - Fix compilation warnings - Ignore unknown character for base64 decoding - Bump minimum targets (for Xcode) - Xcode project disable bitcode (Building with bitcode is deprecated) 1.6.0 - Improve & extend RSA support with DER (see README for details) - Fix Blowfish memory leaks - Fix PCBC mode - SwiftWasm compatibility 1.5.1 - Resolve type name clash by renaming BigInt -> BigInteger 1.5.0 - RSA (@NathanFallet) - Workaround for Xcode 13.3.1 1.4.3 - Fix PCBC mode. 1.4.2 - Update Xcode project to Xcode 13 - Add SHA3 support for HMAC - Update HMAC.Variant API (deprecate current cases) 1.4.1 - Introduce ISO 10126 padding - fix various compiler warnings - Revert Xcode project deployment target 1.4.0 - Customize CFB segment size (cfb8, cfb128). - Adapt Swift @inlineable for better code optimization 1.3.8 - Revert xcframework revolution. Back to build from sources. (I'm sorry) 1.3.7 - Re-release to workaround Swift Package Manager release 1.3.6 - Fix macOS binary - Windows support 1.3.5 - Re-release binary framework due to codesign issue 1.3.4 - Distribute optimized binary (xcframework) via SPM for apple platforms 1.3.3 - Adds OCB Authenticated-Encryption Algorithm (RFC7253) - build-framework.sh output CryptoSwift.xcframework - Xcode 12.2 maintenance updates - Removed CryptoSwift.playground (couldn't make it work since Xcode 12 update) 1.3.2 - Swift 5.3 update (Xcode 12) - Bump target platform (iOS 9, macOS 10.12) - Allow CMAC with any Cipher - Remove CMAC key limit 1.3.1 - Fix tests - Swift 5.2 update - Address possible timing issue 1.3.0 - Adds ISO-78164 padding - Performance improvements - Swift 5.1 update 1.2.0 - Performance improvements - Workaround Xcode test builds with Xcode 11 1.1.3 - Fix build crash: https://bugs.swift.org/browse/SR-11630 - Fixes Xcode project tests build - SwiftFormat all the things - Increase/fix SHA2 data length for big input by use Int64 for calculation 1.1.2 - Fix Swift 5.0 build (for real this time) 1.1.1 - Fix Swift 5.0 build 1.1.0 - Replace RandomBytesSequence with Swift.RandomNumberGenerator - Fix CBC-MAC - Update SPM support - Update for Xcode 11 and Swift 5.1 - Xcode: BUILD_LIBRARY_FOR_DISTRIBUTION = YES 1.0.0 - Swift 5 - Let's - Celebrate - This - Event - With - 1.0.0 release - After - 4 years - Thank you 0.15.0 - Adds The scrypt Password-Based Key Derivation Function (https://tools.ietf.org/html/rfc7914) - Minor improvements 0.14.0 - Fixed decryption of AES-GCM ciphertexts with custom tag length 0.13.1 - Adds AES-GCM tag length configuration. - Fixes count check for initializing UInt64 from Data. 0.13.0 - Adds CBC-MAC authenticator. - Adds AES-CCM operation mode. 0.12.0 - Swift 4.2 maintenance update. 0.11.0 - API: Cryptor.seek() is throwable - Adds proper stream support for CTR encryption with Updaptable interface. - Refactor internals for the stream cipher modes. - Set minimum deployment target to 8.0 (again). 0.10.0 - API: BlockMode is no longer an enum. Please migrate to eg. CBC() etc... - Adds AES-GCM support. #97 - Feature sponsored by GesundheitsCloud (http://www.gesundheitscloud.de/) - Adds CRC32c support. - Improves AES variant validation. - Fixes empty password in PBKDF2. 0.9.0 - Swift 4.1 compatibility - Added CMAC message authenticator https://tools.ietf.org/html/rfc4493 - Added AEADChaCha20Poly1305 (AEAD_CHACHA20_POLY1305) https://tools.ietf.org/html/rfc7539#section-2.8.1 0.8.3 - Fixes SHA3 padding. - Fixes Carthage builds. 0.8.2 - Fixes SHA3 partial updates calculations. - Makes ChaCha20 processing faster again. 0.8.1 - Adds Data(hex:) helper. - Adds HKDF (HMAC-based Extract-and-Expand Key Derivation Function) - Prevent ChaCha overflow error 0.8.0 - Adds SHA3 Keccak variants - Adds String.bytes helper to convert String to array of bytes - Improves AES performance - Speeds up compilation times with Swift 4 - Fixes: Blowfish minimum key size is 5 - Removes Ciphers "iv" parameter (value moved to BlockMode) - BlockMode uses associated value for IV value where apply e.g. .CBC(iv: ivbytes) - Refactors internal hacks no longer needed with Swift 4 0.7.2 - Adds Padding enum (.pkcs5, .pkcs7, .noPadding, .zeroPadding) - Removes Generics from the public API. - Slightly improves SHA1, SHA2, SHA3 performance. - Update SPM configuration for Swift 4 0.7.1 - Swift 4.0 compatibility release 0.7.0 - Swift 3.2 compatibility release 0.6.9 - Fixed padding issue where padding was not properly added in CTR mode. - Fixed thrown error on decrypting empty string, - Fixed CI build script. - Added String.encryptToBase64() 0.6.8 - Speed up MD5() - Faster Array(hex:) - Improve AES performance - Fix tvOS bitcode - Fix Blowfish CFB, OFB, CTR block modes. - Fix Blowfish for 32-bit arch. - Fix ChaCha20 preconditions 0.6.7 - Release for Xcode 8.2 - Fix playground example 0.6.6 - Rework ChaCha20 - Fix Poly1305 0.6.5 - Significant performance improvement when processing lange amount of data. - Degeneric functions and change Sequence -> Collection in generic constraints. 0.6.4 - More performance improvements - Add convenient Digest.sha2(bytes:variant) - New: Blowfish cipher 0.6.3 - Hotfix release - Fixes bitPadding() that breaks Digests calculations, introduced in 0.6.2 0.6.2 - SHA performance improvements by using less Swift in Swift - Fix public access to all digests classes 0.6.1 - Update tests. - New: RandomBytesSequence urandom values on Linux. - Throw appropriate error for AES with invalid input where padding is needed. - Improve performance, especially to SHA-1, SHA-2, PBKDF and related. - Set deployment targets for all platform. Fixes Carthage builds. - New: SHA-3 implementation (request #291) - SHA-1 conforms to Updatable protocol and may be calculated incrementally. - SHA-2 conforms to Updatable protocol and may be calculated incrementally. 0.6.0 - Remove bridge() workaround for Linux (not needed) - make MD5() public - Update README - Convenience HMAC initializer for String input 0.6.0-beta2 - SHA-2 fix #319 - HashProtocol -> Digest and refactor - MD5 conforms to Updatable protocol and may be calculated incrementally - Cipher protocol accepts Collection input now 0.6.0-beta1 - Swift 3 compatibility - Multiplatform, Single-scheme Xcode Project - Swift Package Manager fully supported (build and tests) - Improved Linux support - Travis configuration added - Public interface tests added - enum Authenticator -> protocol Authenticator - CRC -> Checksum - String.encrypt() returns hex string instead of Array - removed String.decrypt() - enum Hash -> struct Hash - Convenience initializer of Array of bytes with Hex string. Array(hex: "0xb1b1b2b2") - Fix reusability of ChaCha20 instance - Replace optional initializers with throwable initializers - Allow to set initial counter explicitly (AES block modes). RandomAccessCryptor.seek() 0.5.2 - Fix AES-CTR incremental updates. #287 - Fixed PBKDF2 tests. #295 - Fixed assertion check in PKCS7. #288 - Updatable protocol accept SequenceType in place of Array 0.5.1 - Fixed PBKDF2 not taking key length parameter into account - Switch to Array<> in code 0.5 - Added PBKDF1 https://tools.ietf.org/html/rfc2898#section-5.1 - Added PBKDF2 https://tools.ietf.org/html/rfc2898#section-5.2 - UpdatableCryptor protocol allows incremental encryption stream of data - CryptoSwift.playground - Docs update - Added reflection control to CRC-32 (Luís Silva) - Fix AES.init() (Pascal Pfiffner) 0.4.1 - fix NoPadding() 0.4 - Padding setup is now part of cipher constructor - Added PBKDF2 http://tools.ietf.org/html/rfc2898#section-5.2 - Add BlockCipher protocol - Rename Cipher -> CipherProtocol - Remove build-frameworks.sh script - Keep sensitive data in memory with SecureBytes - Allows direct use of HMAC and Poly1305 - README update - Fix missing Foundation import on Linux 0.3.1 - replace deprecated Bit with new enum. 0.3 - Swift 2.2 support - use generators for cipher block modes should reduce memory overload. - add OFB block mode - add PCBC block mode - String.decryptBase64ToString to decrypt Base64 encoded strings - broke up complicated expressions which were taking ages to compile 0.2.3 - enable bitcode setting for Debug on an Apple TV - faster compilation times - improve padding functions 0.2.2 - Fix ChaCha20 cipher - Replace for(;;) with for-in - Workaround for "NSString are not yet implicitly convertible to String" on Linux 0.2.1 - Fix linux build - re-add umbrella header 0.2 - Rabbit cipher (RFC4503) - Linux Swift support - Swift Package Manager support - tvOS support - Add optional seed to CRC - Add umbrella header (CryptoSwift.h) - Fix AES in CTR mode - Fix no padding support for CTR and CFB block modes - Fix access to AES.Error and ChaCha20.Error 0.1.1 - Fix Cococapods package (missing Foundation integration) 0.1.0 - Major performance improvements. - Transition from Optionals to throw error. - Replace enum Cipher with protocol for ciphers. - Added CRC16 - Fixed AES CFB decryption - Drop internal "Foundation" dependency, nonetheless it is supported as usual. 0.0.16 - Critical fix for private "md5" selector issue (#135) 0.0.15 - Fix 32-bit CTR block mode - Carthage support update - Mark as App-Extension-Safe API 0.0.14 - hexString -> toHextString() #105 - CTR (Counter mode) - Hex string is lowercase now - Carthage support - Tests update - Swift 2.0 support - overall update ================================================ FILE: CNAME ================================================ cryptoswift.io ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at marcin@krzyzanowskim.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: CONTRIBUTING.md ================================================ By submitting a pull request, you represent that you have the right to license your contribution to Marcin Krzyżanowski and the community, and agree by submitting the patch that your contributions are licensed under the CryptoSwift project license. --- Before submitting the pull request, please make sure you have tested your changes. --- For new files, please use the correct file header: ``` // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // ``` ================================================ FILE: CONTRIBUTORS.txt ================================================ For the purpose of tracking copyright, this is the list of individuals and organizations who have contributed source code to CryptoSwift. ### Contributors - 0xabhisek <128348758+0xabhisek@users.noreply.github.com> - Adin Cebic - Adolfo Martinelli - Aidan Woods - Alejandro Isaza - Alex Binary - Alex Vlasov - AlexDenisov <1101.debian@gmail.com> - Alexey Komnin - Alsey Coleman Miller - Andrew Wagner <845683+drewag@users.noreply.github.com> - André Berenguel - Anton - Ayaka Nonaka - Bart Cone - Bing Cheung <32565605+eungch@users.noreply.github.com> - Bogdan Bystritskiy - Brandon Toms - Brice Cesarin - Bruce Geerdes - Bryan Chen - Bryant Luk - C.W. Betts - Caio Mathielo - Cheng-Yu Hsu - Chris Amanse - Christian Steffens - Cihat Gündüz - Cosmin Baies - Dave Wood - Dima Kalachov - Dusan Klinec - Elaine Lyons - Elias Rad <146735585+nnsW3@users.noreply.github.com> - Eneko Alonso - Eugene Berdnikov - Evan Maloney - Evin Ugur - Frank Langel - Frank Langel - Franklin Schrans - FreeThinker <59345560+Free-FreeThinker@users.noreply.github.com> - Grzegorz Nowicki - Hamilton Chapman - Honza Dvorsky - Howtin - Ibrahim Kteish - Igor Camilo - JP Simard - Javier Soto - Jeremy Greenwood - Jimmie Johansson - John Hammerlund - Jonas Obrist - K.K. POON - Katrin Annuk - Keith Smiley - Kenji Wada - Koray Koska - Kyle Fuller - LamTrinh.Dev - Lex Tang - Logan Wright - Ludo Galabru - Luis Reisewitz - Luís Silva - Madhava Jay - Marc Prud'hommeaux - Marcelo Fabri - Marcin Krzyzanowski - Masayuki Ono - Matias Cudich - Matias Piipari - Matthew Chung - Matthias Geihs - Maxence Mottard - Michael Ledin - Michael Redig - Mikael LE GOFF - Mo Ramezanpoor - Nabil Elqatib - Nate West - Nathan Fallet - Nicholas Maccharoli - Nobutaka Yuasa - Oscar Choi - Oscar De Moya - Pantelis Zirinis - Paolo Musolino - Pascal Pfiffner - Pedro Silva - Pierpaolo Frasa - Quinn McHenry - R4v3nPr0 - Rich Lowenberg - Roman Podymov - Ronald Mannak - SLboat - Sali0m - Sam - Sam Soffes - Samuel GRAU - ScottieY - Semen Zhydenko - Simon Hartmann - Stefan Hintz - Thomas Bibby - Thomas Haak - TictoDev - Tomas Kraina - Tomasz Szulc - Tomasz Wierzbik - Valeriy Van - WFrost3 <134406901+WFrost3@users.noreply.github.com> - Xavier Matos - Yannick Loriot - YinYuGuang - Yury Lapitsky - Zsombor Szabo - Zsombor Szabo - akreutz <27BBsan08!> - dropbigfish - jose - mrahmiao - planetBoy <140164174+Guayaba221@users.noreply.github.com> - spatno - sweepty - venj - Исаев Владислав Игоревич **Updating this list** Please do not edit this file manually. It is generated using `./scripts/generate-contributors-list.sh`. If a name is misspelled or appearing multiple times: add an entry in `./.mailmap` ================================================ FILE: CryptoSwift-TestHostApp/AppDelegate.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. true } func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. } func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. } func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } } ================================================ FILE: CryptoSwift-TestHostApp/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleVersion 1 LSRequiresIPhoneOS UIRequiredDeviceCapabilities armv7 UIRequiresFullScreen UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: CryptoSwift.podspec ================================================ Pod::Spec.new do |s| s.name = "CryptoSwift" s.version = "1.9.0" s.source = { :git => "https://github.com/krzyzanowskim/CryptoSwift.git", :tag => "#{s.version}" } s.summary = "Cryptography in Swift. SHA, MD5, CRC, PBKDF, Poly1305, HMAC, CMAC, HDKF, Scrypt, ChaCha20, Rabbit, Blowfish, AES, RSA." s.description = "Cryptography functions and helpers for Swift implemented in Swift. SHA-1, SHA-2, SHA-3, MD5, PBKDF1, PBKDF2, Scrypt, CRC, Poly1305, HMAC, ChaCha20, Rabbit, Blowfish, AES, RSA" s.homepage = "https://github.com/krzyzanowskim/CryptoSwift" s.license = {:type => "Attribution", :file => "LICENSE"} s.authors = {'Marcin Krzyżanowski' => 'marcin@krzyzanowskim.com'} s.social_media_url = "https://x.com/krzyzanowskim" s.cocoapods_version = '>= 1.10.0' s.swift_version = "5.6" s.ios.deployment_target = "11.0" s.osx.deployment_target = "10.13" s.watchos.deployment_target = "4.0" s.tvos.deployment_target = "11.0" s.source_files = "Sources/CryptoSwift/**/*.swift" s.requires_arc = true s.resource_bundles = {'CryptoSwift' => ['Sources/CryptoSwift/PrivacyInfo.xcprivacy']} end ================================================ FILE: CryptoSwift.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 55; objects = { /* Begin PBXBuildFile section */ 0AF023D5230F2B0F008E4E68 /* ISO78164Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AF023D4230F2B0F008E4E68 /* ISO78164Padding.swift */; }; 0EE73E71204D598100110E11 /* CMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE73E70204D598100110E11 /* CMAC.swift */; }; 0EE73E74204D59C200110E11 /* CMACTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE73E72204D599C00110E11 /* CMACTests.swift */; }; 14156CE52011422400DDCFBC /* ChaCha20Poly1305Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14156CE42011422400DDCFBC /* ChaCha20Poly1305Tests.swift */; }; 1467460F2017BB3600DF04ED /* AEAD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1467460E2017BB3600DF04ED /* AEAD.swift */; }; 35F3E51C23BF9A6700A024A1 /* OCB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35F3E51B23BF9A6700A024A1 /* OCB.swift */; }; 42012783267A6F1C00F82506 /* ISO10126Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42012782267A6F1C00F82506 /* ISO10126Padding.swift */; }; 5431FD5B2B021476001DEE77 /* SignatureVerificationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5431FD592B021470001DEE77 /* SignatureVerificationTests.swift */; }; 674A736F1BF5D85B00866C5B /* RabbitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674A736E1BF5D85B00866C5B /* RabbitTests.swift */; }; 6A7CDEED26CD1E4C00FFB1AF /* RSATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7CDEEC26CD1E4C00FFB1AF /* RSATests.swift */; }; 6AC893F626DB950F00F7E787 /* Addition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893E026DB950C00F7E787 /* Addition.swift */; }; 6AC893F826DB950F00F7E787 /* GCD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893E226DB950D00F7E787 /* GCD.swift */; }; 6AC893F926DB950F00F7E787 /* Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893E326DB950D00F7E787 /* Comparable.swift */; }; 6AC893FA26DB950F00F7E787 /* Hashable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893E426DB950D00F7E787 /* Hashable.swift */; }; 6AC893FC26DB950F00F7E787 /* Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893E626DB950D00F7E787 /* Codable.swift */; }; 6AC893FD26DB950F00F7E787 /* Shifts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893E726DB950D00F7E787 /* Shifts.swift */; }; 6AC8940026DB950F00F7E787 /* Subtraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893EA26DB950D00F7E787 /* Subtraction.swift */; }; 6AC8940226DB950F00F7E787 /* Multiplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893EC26DB950D00F7E787 /* Multiplication.swift */; }; 6AC8940526DB950F00F7E787 /* Strideable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893EF26DB950E00F7E787 /* Strideable.swift */; }; 6AC8940626DB950F00F7E787 /* BigInt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893F026DB950E00F7E787 /* BigInt.swift */; }; 6AC8940726DB950F00F7E787 /* Exponentiation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893F126DB950E00F7E787 /* Exponentiation.swift */; }; 6AC8940826DB950F00F7E787 /* Random.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893F226DB950E00F7E787 /* Random.swift */; }; 6AC8940A26DB950F00F7E787 /* BigUInt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893F426DB950E00F7E787 /* BigUInt.swift */; }; 6AC8940B26DB950F00F7E787 /* Division.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC893F526DB950E00F7E787 /* Division.swift */; }; 750509991F6BEF2A00394A1B /* PKCS7.swift in Sources */ = {isa = PBXBuildFile; fileRef = 750509981F6BEF2A00394A1B /* PKCS7.swift */; }; 7507705F28D61E78004A44DC /* RSA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7507705C28D61E78004A44DC /* RSA.swift */; }; 7507706028D61E78004A44DC /* RSA+Signature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7507705D28D61E78004A44DC /* RSA+Signature.swift */; }; 7507706128D61E78004A44DC /* RSA+Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7507705E28D61E78004A44DC /* RSA+Cipher.swift */; }; 7507706428D61E8B004A44DC /* DER.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7507706328D61E8B004A44DC /* DER.swift */; }; 7507706A28D61E97004A44DC /* ASN1Scanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7507706628D61E97004A44DC /* ASN1Scanner.swift */; }; 7507706B28D61E97004A44DC /* ASN1Encoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7507706728D61E97004A44DC /* ASN1Encoder.swift */; }; 7507706C28D61E97004A44DC /* ASN1Decoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7507706828D61E97004A44DC /* ASN1Decoder.swift */; }; 7507706D28D61E97004A44DC /* ASN1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7507706928D61E97004A44DC /* ASN1.swift */; }; 7507706F28D61EBA004A44DC /* PKCS1v15.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7507706E28D61EBA004A44DC /* PKCS1v15.swift */; }; 7507707128D61ED5004A44DC /* Signature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7507707028D61ED5004A44DC /* Signature.swift */; }; 750CC3EB1DC0CACE0096BE6E /* BlowfishTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 750CC3EA1DC0CACE0096BE6E /* BlowfishTests.swift */; }; 75100F8F19B0BC890005C5F5 /* Poly1305Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75100F8E19B0BC890005C5F5 /* Poly1305Tests.swift */; }; 751AA0F3255F4EB600D4719E /* AESOCBTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35F3E51D23BF9AD300A024A1 /* AESOCBTests.swift */; }; 751EE9781F93996100161FFC /* AES.Cryptors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 751EE9771F93996100161FFC /* AES.Cryptors.swift */; }; 75211F95207249D8004E41F8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75211F94207249D8004E41F8 /* AppDelegate.swift */; }; 7523742D2083C61D0016D662 /* GCM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7523742C2083C61C0016D662 /* GCM.swift */; }; 7529366A20683DFC00195874 /* AEADChaCha20Poly1305.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7529366920683DFC00195874 /* AEADChaCha20Poly1305.swift */; }; 752BED9D208C120D00FC4743 /* Blowfish+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52541EE8B6CA0048EB3B /* Blowfish+Foundation.swift */; }; 752BED9E208C121000FC4743 /* Blowfish.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52491EE8B6CA0048EB3B /* Blowfish.swift */; }; 752BED9F208C135700FC4743 /* AES+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52531EE8B6CA0048EB3B /* AES+Foundation.swift */; }; 753674072175D012003E32A6 /* StreamDecryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 753674062175D012003E32A6 /* StreamDecryptor.swift */; }; 754310442050111A003FB1DF /* CompactMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754310432050111A003FB1DF /* CompactMap.swift */; }; 75482EA41CB310B7001F66A5 /* PBKDF.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75482EA31CB310B7001F66A5 /* PBKDF.swift */; }; 754BE46819693E190098E6F3 /* DigestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 754BE46719693E190098E6F3 /* DigestTests.swift */; }; 755BA296235387700039CAB5 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7576F64C20725BD5006688F8 /* Default-568h@2x.png */; }; 755FB1DA199E347D00475437 /* ExtensionsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755FB1D9199E347D00475437 /* ExtensionsTest.swift */; }; 7564F0522072EAEB00CA5A96 /* PBKDFPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7576F6F6207290F8006688F8 /* PBKDFPerf.swift */; platformFilter = ios; }; 7564F0532072EAEB00CA5A96 /* ChaCha20TestsPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7576F6F020728EAB006688F8 /* ChaCha20TestsPerf.swift */; platformFilter = ios; }; 7564F0542072EAEB00CA5A96 /* RabbitTestsPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7576F6F220728F00006688F8 /* RabbitTestsPerf.swift */; platformFilter = ios; }; 7564F0552072EAEB00CA5A96 /* ExtensionsTestPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7576F6F420729069006688F8 /* ExtensionsTestPerf.swift */; platformFilter = ios; }; 7564F0562072EAEB00CA5A96 /* DigestTestsPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7576F6EB20726319006688F8 /* DigestTestsPerf.swift */; platformFilter = ios; }; 7564F0582072EAEB00CA5A96 /* AESTestsPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7576F6EE20726422006688F8 /* AESTestsPerf.swift */; platformFilter = ios; }; 7564F05A2072EAEB00CA5A96 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 754BE45519693E190098E6F3 /* CryptoSwift.framework */; }; 7564F0642072ED7000CA5A96 /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 754BE45519693E190098E6F3 /* CryptoSwift.framework */; }; 7564F0652072ED7000CA5A96 /* CryptoSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 754BE45519693E190098E6F3 /* CryptoSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 756A64C62111083B00BE8805 /* StreamEncryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756A64C52111083B00BE8805 /* StreamEncryptor.swift */; }; 7571938E2816BFE3001C3AC0 /* CS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7571938D2816BFE3001C3AC0 /* CS.swift */; }; 757DA2531A4ED0A4002BA3EF /* PaddingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757DA2521A4ED0A4002BA3EF /* PaddingTests.swift */; }; 757DA2551A4ED408002BA3EF /* AESTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757DA2541A4ED408002BA3EF /* AESTests.swift */; }; 757DA2591A4ED4D7002BA3EF /* ChaCha20Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757DA2581A4ED4D7002BA3EF /* ChaCha20Tests.swift */; }; 758A94291A65C67400E46135 /* HMACTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 758A94271A65C59200E46135 /* HMACTests.swift */; }; 7594CCBC217A76DC0055C95D /* AESCCMTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 755E0303217A756F00065FC6 /* AESCCMTests.swift */; }; 7595C1582072E5B900EA1A5F /* DigestTestsPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7576F6EB20726319006688F8 /* DigestTestsPerf.swift */; platformFilters = (macos, ); }; 7595C1592072E5B900EA1A5F /* AESTestsPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7576F6EE20726422006688F8 /* AESTestsPerf.swift */; platformFilters = (macos, ); }; 7595C15A2072E5B900EA1A5F /* ChaCha20TestsPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7576F6F020728EAB006688F8 /* ChaCha20TestsPerf.swift */; platformFilters = (macos, ); }; 7595C15B2072E5B900EA1A5F /* RabbitTestsPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7576F6F220728F00006688F8 /* RabbitTestsPerf.swift */; platformFilters = (macos, ); }; 7595C15C2072E5B900EA1A5F /* ExtensionsTestPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7576F6F420729069006688F8 /* ExtensionsTestPerf.swift */; platformFilters = (macos, ); }; 7595C15D2072E5B900EA1A5F /* PBKDFPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7576F6F6207290F8006688F8 /* PBKDFPerf.swift */; platformFilters = (macos, ); }; 7595C1602072E64900EA1A5F /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 754BE45519693E190098E6F3 /* CryptoSwift.framework */; }; 75B3ED77210F9DF7005D4ADA /* BlockDecryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75B3ED76210F9DF7005D4ADA /* BlockDecryptor.swift */; }; 75B3ED79210FA016005D4ADA /* BlockEncryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75B3ED78210FA016005D4ADA /* BlockEncryptor.swift */; }; 75B601EB197D6A6C0009B53D /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 754BE45519693E190098E6F3 /* CryptoSwift.framework */; }; 75C2E76D1D55F097003D2BCA /* Access.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75C2E76C1D55F097003D2BCA /* Access.swift */; }; 75D7AF38208BFB1600D22BEB /* UInt128.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D7AF37208BFB1600D22BEB /* UInt128.swift */; }; 75EC527B1EE8B73A0048EB3B /* CryptoSwift.h in Headers */ = {isa = PBXBuildFile; fileRef = 75EC527A1EE8B6CA0048EB3B /* CryptoSwift.h */; settings = {ATTRIBUTES = (Public, ); }; }; 75EC527C1EE8B8130048EB3B /* AES.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52381EE8B6CA0048EB3B /* AES.swift */; }; 75EC527D1EE8B8130048EB3B /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52391EE8B6CA0048EB3B /* Array+Extension.swift */; }; 75EC527E1EE8B8130048EB3B /* Authenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC523A1EE8B6CA0048EB3B /* Authenticator.swift */; }; 75EC527F1EE8B8130048EB3B /* BatchedCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC523B1EE8B6CA0048EB3B /* BatchedCollection.swift */; }; 75EC52801EE8B8130048EB3B /* Bit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC523C1EE8B6CA0048EB3B /* Bit.swift */; }; 75EC52811EE8B8130048EB3B /* BlockCipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC523D1EE8B6CA0048EB3B /* BlockCipher.swift */; }; 75EC52821EE8B8170048EB3B /* BlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC523F1EE8B6CA0048EB3B /* BlockMode.swift */; }; 75EC52831EE8B8170048EB3B /* BlockModeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52401EE8B6CA0048EB3B /* BlockModeOptions.swift */; }; 75EC52841EE8B8170048EB3B /* CipherModeWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52411EE8B6CA0048EB3B /* CipherModeWorker.swift */; }; 75EC52851EE8B8170048EB3B /* CBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52421EE8B6CA0048EB3B /* CBC.swift */; }; 75EC52861EE8B8170048EB3B /* CFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52431EE8B6CA0048EB3B /* CFB.swift */; }; 75EC52871EE8B8170048EB3B /* CTR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52441EE8B6CA0048EB3B /* CTR.swift */; }; 75EC52881EE8B8170048EB3B /* ECB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52451EE8B6CA0048EB3B /* ECB.swift */; }; 75EC52891EE8B8170048EB3B /* OFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52461EE8B6CA0048EB3B /* OFB.swift */; }; 75EC528A1EE8B8170048EB3B /* PCBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52471EE8B6CA0048EB3B /* PCBC.swift */; }; 75EC528D1EE8B81A0048EB3B /* ChaCha20.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC524A1EE8B6CA0048EB3B /* ChaCha20.swift */; }; 75EC528E1EE8B81A0048EB3B /* Checksum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC524B1EE8B6CA0048EB3B /* Checksum.swift */; }; 75EC528F1EE8B81A0048EB3B /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC524C1EE8B6CA0048EB3B /* Cipher.swift */; }; 75EC52901EE8B81A0048EB3B /* Collection+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC524D1EE8B6CA0048EB3B /* Collection+Extension.swift */; }; 75EC52911EE8B81A0048EB3B /* Cryptors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC524E1EE8B6CA0048EB3B /* Cryptors.swift */; }; 75EC52931EE8B81A0048EB3B /* Digest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52501EE8B6CA0048EB3B /* Digest.swift */; }; 75EC52941EE8B81A0048EB3B /* DigestType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52511EE8B6CA0048EB3B /* DigestType.swift */; }; 75EC52971EE8B8200048EB3B /* ChaCha20+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52551EE8B6CA0048EB3B /* ChaCha20+Foundation.swift */; }; 75EC52981EE8B8200048EB3B /* Array+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52561EE8B6CA0048EB3B /* Array+Foundation.swift */; }; 75EC52991EE8B8200048EB3B /* Data+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52571EE8B6CA0048EB3B /* Data+Extension.swift */; }; 75EC529A1EE8B8200048EB3B /* HMAC+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52581EE8B6CA0048EB3B /* HMAC+Foundation.swift */; }; 75EC529B1EE8B8200048EB3B /* Rabbit+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52591EE8B6CA0048EB3B /* Rabbit+Foundation.swift */; }; 75EC529C1EE8B8200048EB3B /* String+FoundationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC525A1EE8B6CA0048EB3B /* String+FoundationExtension.swift */; }; 75EC529D1EE8B8200048EB3B /* Utils+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC525B1EE8B6CA0048EB3B /* Utils+Foundation.swift */; }; 75EC529E1EE8B8230048EB3B /* Generics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC525C1EE8B6CA0048EB3B /* Generics.swift */; }; 75EC529F1EE8B8230048EB3B /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC525D1EE8B6CA0048EB3B /* HMAC.swift */; }; 75EC52A01EE8B8290048EB3B /* Int+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC525F1EE8B6CA0048EB3B /* Int+Extension.swift */; }; 75EC52A21EE8B8290048EB3B /* MD5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52611EE8B6CA0048EB3B /* MD5.swift */; }; 75EC52A31EE8B8290048EB3B /* NoPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52621EE8B6CA0048EB3B /* NoPadding.swift */; }; 75EC52A41EE8B8290048EB3B /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52631EE8B6CA0048EB3B /* Operators.swift */; }; 75EC52A51EE8B8290048EB3B /* Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52641EE8B6CA0048EB3B /* Padding.swift */; }; 75EC52A61EE8B8390048EB3B /* PBKDF1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52661EE8B6CA0048EB3B /* PBKDF1.swift */; }; 75EC52A71EE8B8390048EB3B /* PBKDF2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52671EE8B6CA0048EB3B /* PBKDF2.swift */; }; 75EC52A81EE8B8390048EB3B /* PKCS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52681EE8B6CA0048EB3B /* PKCS5.swift */; }; 75EC52A91EE8B83D0048EB3B /* PKCS7Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52691EE8B6CA0048EB3B /* PKCS7Padding.swift */; }; 75EC52AA1EE8B83D0048EB3B /* Poly1305.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC526A1EE8B6CA0048EB3B /* Poly1305.swift */; }; 75EC52AB1EE8B83D0048EB3B /* Rabbit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC526B1EE8B6CA0048EB3B /* Rabbit.swift */; }; 75EC52AC1EE8B83D0048EB3B /* Cryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC526C1EE8B6CA0048EB3B /* Cryptor.swift */; }; 75EC52AE1EE8B83D0048EB3B /* SecureBytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC526E1EE8B6CA0048EB3B /* SecureBytes.swift */; }; 75EC52AF1EE8B83D0048EB3B /* SHA1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC526F1EE8B6CA0048EB3B /* SHA1.swift */; }; 75EC52B01EE8B83D0048EB3B /* SHA2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52701EE8B6CA0048EB3B /* SHA2.swift */; }; 75EC52B11EE8B83D0048EB3B /* SHA3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52711EE8B6CA0048EB3B /* SHA3.swift */; }; 75EC52B21EE8B83D0048EB3B /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52721EE8B6CA0048EB3B /* String+Extension.swift */; }; 75EC52B31EE8B83D0048EB3B /* UInt16+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52731EE8B6CA0048EB3B /* UInt16+Extension.swift */; }; 75EC52B41EE8B83D0048EB3B /* UInt32+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52741EE8B6CA0048EB3B /* UInt32+Extension.swift */; }; 75EC52B51EE8B83D0048EB3B /* UInt64+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52751EE8B6CA0048EB3B /* UInt64+Extension.swift */; }; 75EC52B61EE8B83D0048EB3B /* UInt8+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52761EE8B6CA0048EB3B /* UInt8+Extension.swift */; }; 75EC52B71EE8B83D0048EB3B /* Updatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52771EE8B6CA0048EB3B /* Updatable.swift */; }; 75EC52B81EE8B83D0048EB3B /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52781EE8B6CA0048EB3B /* Utils.swift */; }; 75EC52B91EE8B83D0048EB3B /* ZeroPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EC52791EE8B6CA0048EB3B /* ZeroPadding.swift */; }; 75F4E434216C93EF00F09710 /* CCM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F4E433216C93EF00F09710 /* CCM.swift */; }; 75F4E436216C98DE00F09710 /* CBCMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F4E435216C98DE00F09710 /* CBCMAC.swift */; }; 81F279DD2181F58300449EDA /* Scrypt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81F279DC2181F58300449EDA /* Scrypt.swift */; }; 81F279DF2181F5A000449EDA /* ScryptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81F279DE2181F5A000449EDA /* ScryptTests.swift */; }; 81F279E12181F5C500449EDA /* ScryptTestsPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81F279E02181F5C500449EDA /* ScryptTestsPerf.swift */; platformFilters = (macos, ); }; 81F279E22181F5C500449EDA /* ScryptTestsPerf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81F279E02181F5C500449EDA /* ScryptTestsPerf.swift */; platformFilter = ios; }; AA54CF312B860926006BF411 /* PrivacyInfo.xcprivacy in CopyFiles */ = {isa = PBXBuildFile; fileRef = 75C454012B4B6EBC00FC5020 /* PrivacyInfo.xcprivacy */; }; E3FD2D531D6B81CE00A9F35F /* Error+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3FD2D511D6B813C00A9F35F /* Error+Extension.swift */; }; E6200E141FB9A7AE00258382 /* HKDF.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6200E131FB9A7AE00258382 /* HKDF.swift */; }; E6200E171FB9B68C00258382 /* HKDFTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6200E151FB9B67C00258382 /* HKDFTests.swift */; }; EC353DB42BECCEFD0026B46B /* BitwiseOps.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC353DB32BECCEFD0026B46B /* BitwiseOps.swift */; }; EC353DB62BECCF3A0026B46B /* DataConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC353DB52BECCF3A0026B46B /* DataConversion.swift */; }; EC353DB82BECCF4B0026B46B /* FloatingPointConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC353DB72BECCF4B0026B46B /* FloatingPointConversion.swift */; }; EC353DBA2BECCF5A0026B46B /* IntegerConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC353DB92BECCF5A0026B46B /* IntegerConversion.swift */; }; EC353DBC2BECCF6A0026B46B /* PrimeTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC353DBB2BECCF6A0026B46B /* PrimeTest.swift */; }; EC353DBE2BECCF770026B46B /* SquareRoot.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC353DBD2BECCF770026B46B /* SquareRoot.swift */; }; EC353DC02BECCF860026B46B /* StringConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC353DBF2BECCF860026B46B /* StringConversion.swift */; }; EC353DC22BECCF8F0026B46B /* WordsAndBits.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC353DC12BECCF8F0026B46B /* WordsAndBits.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 7564F0502072EAEB00CA5A96 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 754BE44C19693E190098E6F3 /* Project object */; proxyType = 1; remoteGlobalIDString = 754BE45419693E190098E6F3; remoteInfo = CryptoSwift; }; 7564F0612072EB5D00CA5A96 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 754BE44C19693E190098E6F3 /* Project object */; proxyType = 1; remoteGlobalIDString = 75211F91207249D8004E41F8; remoteInfo = "CryptoSwift-TestHostApp"; }; 7564F0662072ED7000CA5A96 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 754BE44C19693E190098E6F3 /* Project object */; proxyType = 1; remoteGlobalIDString = 754BE45419693E190098E6F3; remoteInfo = CryptoSwift; }; 7595C15E2072E64000EA1A5F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 754BE44C19693E190098E6F3 /* Project object */; proxyType = 1; remoteGlobalIDString = 754BE45419693E190098E6F3; remoteInfo = CryptoSwift; }; 75B601E3197D69EB0009B53D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 754BE44C19693E190098E6F3 /* Project object */; proxyType = 1; remoteGlobalIDString = 754BE45419693E190098E6F3; remoteInfo = CryptoSwift; }; 75F9482120BDDF9900956311 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 754BE44C19693E190098E6F3 /* Project object */; proxyType = 1; remoteGlobalIDString = 75211F91207249D8004E41F8; remoteInfo = "CryptoSwift-TestHostApp"; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 7564F0682072ED7000CA5A96 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( 7564F0652072ED7000CA5A96 /* CryptoSwift.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; 75B601E0197D69770009B53D /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 7; files = ( AA54CF312B860926006BF411 /* PrivacyInfo.xcprivacy in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 0AF023D4230F2B0F008E4E68 /* ISO78164Padding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ISO78164Padding.swift; sourceTree = ""; }; 0EE73E70204D598100110E11 /* CMAC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CMAC.swift; sourceTree = ""; }; 0EE73E72204D599C00110E11 /* CMACTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CMACTests.swift; sourceTree = ""; }; 14156CE42011422400DDCFBC /* ChaCha20Poly1305Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChaCha20Poly1305Tests.swift; sourceTree = ""; }; 1467460E2017BB3600DF04ED /* AEAD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AEAD.swift; sourceTree = ""; }; 35F3E51B23BF9A6700A024A1 /* OCB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OCB.swift; sourceTree = ""; }; 35F3E51D23BF9AD300A024A1 /* AESOCBTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AESOCBTests.swift; sourceTree = ""; }; 42012782267A6F1C00F82506 /* ISO10126Padding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ISO10126Padding.swift; sourceTree = ""; }; 5431FD592B021470001DEE77 /* SignatureVerificationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignatureVerificationTests.swift; sourceTree = ""; }; 674A736E1BF5D85B00866C5B /* RabbitTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RabbitTests.swift; sourceTree = ""; }; 6A7CDEEC26CD1E4C00FFB1AF /* RSATests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSATests.swift; sourceTree = ""; }; 6AC893E026DB950C00F7E787 /* Addition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Addition.swift; sourceTree = ""; }; 6AC893E226DB950D00F7E787 /* GCD.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GCD.swift; sourceTree = ""; }; 6AC893E326DB950D00F7E787 /* Comparable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comparable.swift; sourceTree = ""; }; 6AC893E426DB950D00F7E787 /* Hashable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Hashable.swift; sourceTree = ""; }; 6AC893E626DB950D00F7E787 /* Codable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Codable.swift; sourceTree = ""; }; 6AC893E726DB950D00F7E787 /* Shifts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Shifts.swift; sourceTree = ""; }; 6AC893EA26DB950D00F7E787 /* Subtraction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Subtraction.swift; sourceTree = ""; }; 6AC893EC26DB950D00F7E787 /* Multiplication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Multiplication.swift; sourceTree = ""; }; 6AC893EF26DB950E00F7E787 /* Strideable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Strideable.swift; sourceTree = ""; }; 6AC893F026DB950E00F7E787 /* BigInt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BigInt.swift; sourceTree = ""; }; 6AC893F126DB950E00F7E787 /* Exponentiation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Exponentiation.swift; sourceTree = ""; }; 6AC893F226DB950E00F7E787 /* Random.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Random.swift; sourceTree = ""; }; 6AC893F426DB950E00F7E787 /* BigUInt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BigUInt.swift; sourceTree = ""; }; 6AC893F526DB950E00F7E787 /* Division.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Division.swift; sourceTree = ""; }; 750509981F6BEF2A00394A1B /* PKCS7.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PKCS7.swift; sourceTree = ""; }; 7507705C28D61E78004A44DC /* RSA.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RSA.swift; sourceTree = ""; }; 7507705D28D61E78004A44DC /* RSA+Signature.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RSA+Signature.swift"; sourceTree = ""; }; 7507705E28D61E78004A44DC /* RSA+Cipher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RSA+Cipher.swift"; sourceTree = ""; }; 7507706328D61E8B004A44DC /* DER.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DER.swift; sourceTree = ""; }; 7507706628D61E97004A44DC /* ASN1Scanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1Scanner.swift; sourceTree = ""; }; 7507706728D61E97004A44DC /* ASN1Encoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1Encoder.swift; sourceTree = ""; }; 7507706828D61E97004A44DC /* ASN1Decoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1Decoder.swift; sourceTree = ""; }; 7507706928D61E97004A44DC /* ASN1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ASN1.swift; sourceTree = ""; }; 7507706E28D61EBA004A44DC /* PKCS1v15.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PKCS1v15.swift; sourceTree = ""; }; 7507707028D61ED5004A44DC /* Signature.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signature.swift; sourceTree = ""; }; 750CC3EA1DC0CACE0096BE6E /* BlowfishTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlowfishTests.swift; sourceTree = ""; }; 75100F8E19B0BC890005C5F5 /* Poly1305Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Poly1305Tests.swift; sourceTree = ""; }; 751EE9771F93996100161FFC /* AES.Cryptors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AES.Cryptors.swift; sourceTree = ""; }; 75211F92207249D8004E41F8 /* CryptoSwift-TestHostApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "CryptoSwift-TestHostApp.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 75211F94207249D8004E41F8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 75211FA0207249D8004E41F8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 75211FA520724A0F004E41F8 /* CryptoSwift-TestHostApp-Test.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "CryptoSwift-TestHostApp-Test.xcconfig"; sourceTree = ""; }; 75211FA820724A0F004E41F8 /* CryptoSwift-Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "CryptoSwift-Shared.xcconfig"; sourceTree = ""; }; 75211FA920724A0F004E41F8 /* CryptoSwift-TestHostApp-Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "CryptoSwift-TestHostApp-Shared.xcconfig"; sourceTree = ""; }; 75211FAA20724A0F004E41F8 /* Project-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Project-Release.xcconfig"; sourceTree = ""; }; 75211FAC20724A0F004E41F8 /* CryptoSwift-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "CryptoSwift-Release.xcconfig"; sourceTree = ""; }; 75211FAE20724A10004E41F8 /* Tests-Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Tests-Shared.xcconfig"; sourceTree = ""; }; 75211FAF20724A10004E41F8 /* CryptoSwift-Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "CryptoSwift-Debug.xcconfig"; sourceTree = ""; }; 75211FB020724A10004E41F8 /* Project-Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Project-Debug.xcconfig"; sourceTree = ""; }; 75211FB120724A10004E41F8 /* Tests-Test.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Tests-Test.xcconfig"; sourceTree = ""; }; 75211FB220724A10004E41F8 /* Project-Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Project-Shared.xcconfig"; sourceTree = ""; }; 75211FB420724A10004E41F8 /* CryptoSwift-Test.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "CryptoSwift-Test.xcconfig"; sourceTree = ""; }; 7523742C2083C61C0016D662 /* GCM.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GCM.swift; sourceTree = ""; }; 7529366920683DFC00195874 /* AEADChaCha20Poly1305.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AEADChaCha20Poly1305.swift; sourceTree = ""; }; 753674062175D012003E32A6 /* StreamDecryptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StreamDecryptor.swift; sourceTree = ""; }; 7536A93E207254A000F39140 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; 754310432050111A003FB1DF /* CompactMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactMap.swift; sourceTree = ""; }; 75482EA31CB310B7001F66A5 /* PBKDF.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBKDF.swift; sourceTree = ""; }; 754BE45519693E190098E6F3 /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 754BE46019693E190098E6F3 /* CryptoSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CryptoSwiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 754BE46719693E190098E6F3 /* DigestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DigestTests.swift; sourceTree = ""; }; 755E0303217A756F00065FC6 /* AESCCMTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AESCCMTests.swift; sourceTree = ""; }; 755FB1D9199E347D00475437 /* ExtensionsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionsTest.swift; sourceTree = ""; }; 7564F0602072EAEB00CA5A96 /* TestsPerformance-iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "TestsPerformance-iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 756A64C52111083B00BE8805 /* StreamEncryptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StreamEncryptor.swift; sourceTree = ""; }; 756BFDCA1A82B87300B9D9A4 /* Bridging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Bridging.h; sourceTree = ""; }; 7571938D2816BFE3001C3AC0 /* CS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CS.swift; sourceTree = ""; }; 7576F64C20725BD5006688F8 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 7576F6EB20726319006688F8 /* DigestTestsPerf.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DigestTestsPerf.swift; sourceTree = ""; }; 7576F6EE20726422006688F8 /* AESTestsPerf.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AESTestsPerf.swift; sourceTree = ""; }; 7576F6F020728EAB006688F8 /* ChaCha20TestsPerf.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChaCha20TestsPerf.swift; sourceTree = ""; }; 7576F6F220728F00006688F8 /* RabbitTestsPerf.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RabbitTestsPerf.swift; sourceTree = ""; }; 7576F6F420729069006688F8 /* ExtensionsTestPerf.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionsTestPerf.swift; sourceTree = ""; }; 7576F6F6207290F8006688F8 /* PBKDFPerf.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PBKDFPerf.swift; sourceTree = ""; }; 757DA2521A4ED0A4002BA3EF /* PaddingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaddingTests.swift; sourceTree = ""; }; 757DA2541A4ED408002BA3EF /* AESTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AESTests.swift; sourceTree = ""; }; 757DA2581A4ED4D7002BA3EF /* ChaCha20Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChaCha20Tests.swift; sourceTree = ""; }; 758A94271A65C59200E46135 /* HMACTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HMACTests.swift; sourceTree = ""; }; 7595C14A2072E48C00EA1A5F /* TestsPerformance-Mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "TestsPerformance-Mac.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 75B3ED76210F9DF7005D4ADA /* BlockDecryptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockDecryptor.swift; sourceTree = ""; }; 75B3ED78210FA016005D4ADA /* BlockEncryptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockEncryptor.swift; sourceTree = ""; }; 75C2E76C1D55F097003D2BCA /* Access.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Access.swift; sourceTree = ""; }; 75C454012B4B6EBC00FC5020 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = Sources/CryptoSwift/PrivacyInfo.xcprivacy; sourceTree = ""; }; 75D7AF37208BFB1600D22BEB /* UInt128.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UInt128.swift; sourceTree = ""; }; 75EC52381EE8B6CA0048EB3B /* AES.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AES.swift; sourceTree = ""; }; 75EC52391EE8B6CA0048EB3B /* Array+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extension.swift"; sourceTree = ""; }; 75EC523A1EE8B6CA0048EB3B /* Authenticator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Authenticator.swift; sourceTree = ""; }; 75EC523B1EE8B6CA0048EB3B /* BatchedCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchedCollection.swift; sourceTree = ""; }; 75EC523C1EE8B6CA0048EB3B /* Bit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bit.swift; sourceTree = ""; }; 75EC523D1EE8B6CA0048EB3B /* BlockCipher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockCipher.swift; sourceTree = ""; }; 75EC523F1EE8B6CA0048EB3B /* BlockMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockMode.swift; sourceTree = ""; }; 75EC52401EE8B6CA0048EB3B /* BlockModeOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockModeOptions.swift; sourceTree = ""; }; 75EC52411EE8B6CA0048EB3B /* CipherModeWorker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CipherModeWorker.swift; sourceTree = ""; }; 75EC52421EE8B6CA0048EB3B /* CBC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CBC.swift; sourceTree = ""; }; 75EC52431EE8B6CA0048EB3B /* CFB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CFB.swift; sourceTree = ""; }; 75EC52441EE8B6CA0048EB3B /* CTR.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CTR.swift; sourceTree = ""; }; 75EC52451EE8B6CA0048EB3B /* ECB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ECB.swift; sourceTree = ""; }; 75EC52461EE8B6CA0048EB3B /* OFB.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OFB.swift; sourceTree = ""; }; 75EC52471EE8B6CA0048EB3B /* PCBC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PCBC.swift; sourceTree = ""; }; 75EC52491EE8B6CA0048EB3B /* Blowfish.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Blowfish.swift; sourceTree = ""; }; 75EC524A1EE8B6CA0048EB3B /* ChaCha20.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChaCha20.swift; sourceTree = ""; }; 75EC524B1EE8B6CA0048EB3B /* Checksum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checksum.swift; sourceTree = ""; }; 75EC524C1EE8B6CA0048EB3B /* Cipher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cipher.swift; sourceTree = ""; }; 75EC524D1EE8B6CA0048EB3B /* Collection+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+Extension.swift"; sourceTree = ""; }; 75EC524E1EE8B6CA0048EB3B /* Cryptors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cryptors.swift; sourceTree = ""; }; 75EC52501EE8B6CA0048EB3B /* Digest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Digest.swift; sourceTree = ""; }; 75EC52511EE8B6CA0048EB3B /* DigestType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DigestType.swift; sourceTree = ""; }; 75EC52531EE8B6CA0048EB3B /* AES+Foundation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AES+Foundation.swift"; sourceTree = ""; }; 75EC52541EE8B6CA0048EB3B /* Blowfish+Foundation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Blowfish+Foundation.swift"; sourceTree = ""; }; 75EC52551EE8B6CA0048EB3B /* ChaCha20+Foundation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChaCha20+Foundation.swift"; sourceTree = ""; }; 75EC52561EE8B6CA0048EB3B /* Array+Foundation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Foundation.swift"; sourceTree = ""; }; 75EC52571EE8B6CA0048EB3B /* Data+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Extension.swift"; sourceTree = ""; }; 75EC52581EE8B6CA0048EB3B /* HMAC+Foundation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HMAC+Foundation.swift"; sourceTree = ""; }; 75EC52591EE8B6CA0048EB3B /* Rabbit+Foundation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Rabbit+Foundation.swift"; sourceTree = ""; }; 75EC525A1EE8B6CA0048EB3B /* String+FoundationExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+FoundationExtension.swift"; sourceTree = ""; }; 75EC525B1EE8B6CA0048EB3B /* Utils+Foundation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Utils+Foundation.swift"; sourceTree = ""; }; 75EC525C1EE8B6CA0048EB3B /* Generics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Generics.swift; sourceTree = ""; }; 75EC525D1EE8B6CA0048EB3B /* HMAC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HMAC.swift; sourceTree = ""; }; 75EC525F1EE8B6CA0048EB3B /* Int+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Int+Extension.swift"; sourceTree = ""; }; 75EC52611EE8B6CA0048EB3B /* MD5.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MD5.swift; sourceTree = ""; }; 75EC52621EE8B6CA0048EB3B /* NoPadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoPadding.swift; sourceTree = ""; }; 75EC52631EE8B6CA0048EB3B /* Operators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; 75EC52641EE8B6CA0048EB3B /* Padding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Padding.swift; sourceTree = ""; }; 75EC52661EE8B6CA0048EB3B /* PBKDF1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PBKDF1.swift; sourceTree = ""; }; 75EC52671EE8B6CA0048EB3B /* PBKDF2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PBKDF2.swift; sourceTree = ""; }; 75EC52681EE8B6CA0048EB3B /* PKCS5.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PKCS5.swift; sourceTree = ""; }; 75EC52691EE8B6CA0048EB3B /* PKCS7Padding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PKCS7Padding.swift; sourceTree = ""; }; 75EC526A1EE8B6CA0048EB3B /* Poly1305.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Poly1305.swift; sourceTree = ""; }; 75EC526B1EE8B6CA0048EB3B /* Rabbit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Rabbit.swift; sourceTree = ""; }; 75EC526C1EE8B6CA0048EB3B /* Cryptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cryptor.swift; sourceTree = ""; }; 75EC526E1EE8B6CA0048EB3B /* SecureBytes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureBytes.swift; sourceTree = ""; }; 75EC526F1EE8B6CA0048EB3B /* SHA1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SHA1.swift; sourceTree = ""; }; 75EC52701EE8B6CA0048EB3B /* SHA2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SHA2.swift; sourceTree = ""; }; 75EC52711EE8B6CA0048EB3B /* SHA3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SHA3.swift; sourceTree = ""; }; 75EC52721EE8B6CA0048EB3B /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = ""; }; 75EC52731EE8B6CA0048EB3B /* UInt16+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt16+Extension.swift"; sourceTree = ""; }; 75EC52741EE8B6CA0048EB3B /* UInt32+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt32+Extension.swift"; sourceTree = ""; }; 75EC52751EE8B6CA0048EB3B /* UInt64+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt64+Extension.swift"; sourceTree = ""; }; 75EC52761EE8B6CA0048EB3B /* UInt8+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt8+Extension.swift"; sourceTree = ""; }; 75EC52771EE8B6CA0048EB3B /* Updatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Updatable.swift; sourceTree = ""; }; 75EC52781EE8B6CA0048EB3B /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; 75EC52791EE8B6CA0048EB3B /* ZeroPadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZeroPadding.swift; sourceTree = ""; }; 75EC527A1EE8B6CA0048EB3B /* CryptoSwift.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CryptoSwift.h; sourceTree = ""; }; 75F4E433216C93EF00F09710 /* CCM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CCM.swift; sourceTree = ""; }; 75F4E435216C98DE00F09710 /* CBCMAC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CBCMAC.swift; sourceTree = ""; }; 75F4E437216C9B5D00F09710 /* CHANGELOG */ = {isa = PBXFileReference; lastKnownFileType = text; path = CHANGELOG; sourceTree = SOURCE_ROOT; }; 75F4E438216C9B6900F09710 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; 81F279DC2181F58300449EDA /* Scrypt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Scrypt.swift; sourceTree = ""; }; 81F279DE2181F5A000449EDA /* ScryptTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScryptTests.swift; sourceTree = ""; }; 81F279E02181F5C500449EDA /* ScryptTestsPerf.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScryptTestsPerf.swift; sourceTree = ""; }; E3FD2D511D6B813C00A9F35F /* Error+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Error+Extension.swift"; sourceTree = ""; }; E6200E131FB9A7AE00258382 /* HKDF.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HKDF.swift; sourceTree = ""; }; E6200E151FB9B67C00258382 /* HKDFTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HKDFTests.swift; sourceTree = ""; }; EC353DB32BECCEFD0026B46B /* BitwiseOps.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BitwiseOps.swift; sourceTree = ""; }; EC353DB52BECCF3A0026B46B /* DataConversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataConversion.swift; sourceTree = ""; }; EC353DB72BECCF4B0026B46B /* FloatingPointConversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloatingPointConversion.swift; sourceTree = ""; }; EC353DB92BECCF5A0026B46B /* IntegerConversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntegerConversion.swift; sourceTree = ""; }; EC353DBB2BECCF6A0026B46B /* PrimeTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrimeTest.swift; sourceTree = ""; }; EC353DBD2BECCF770026B46B /* SquareRoot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SquareRoot.swift; sourceTree = ""; }; EC353DBF2BECCF860026B46B /* StringConversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringConversion.swift; sourceTree = ""; }; EC353DC12BECCF8F0026B46B /* WordsAndBits.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WordsAndBits.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 75211F8F207249D8004E41F8 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 7564F0642072ED7000CA5A96 /* CryptoSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 754BE45119693E190098E6F3 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 754BE45D19693E190098E6F3 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 75B601EB197D6A6C0009B53D /* CryptoSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 7564F0592072EAEB00CA5A96 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 7564F05A2072EAEB00CA5A96 /* CryptoSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 7595C1472072E48C00EA1A5F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 7595C1602072E64900EA1A5F /* CryptoSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 24B0BBA29D734E62809E53BC /* Frameworks */ = { isa = PBXGroup; children = ( 7536A93E207254A000F39140 /* UIKit.framework */, ); name = Frameworks; sourceTree = ""; }; 6AC893DF26DB94F700F7E787 /* CS_BigInt */ = { isa = PBXGroup; children = ( 6AC893E026DB950C00F7E787 /* Addition.swift */, 6AC893F026DB950E00F7E787 /* BigInt.swift */, 6AC893F426DB950E00F7E787 /* BigUInt.swift */, EC353DB32BECCEFD0026B46B /* BitwiseOps.swift */, 6AC893E626DB950D00F7E787 /* Codable.swift */, 6AC893E326DB950D00F7E787 /* Comparable.swift */, EC353DB52BECCF3A0026B46B /* DataConversion.swift */, 6AC893F526DB950E00F7E787 /* Division.swift */, 6AC893F126DB950E00F7E787 /* Exponentiation.swift */, EC353DB72BECCF4B0026B46B /* FloatingPointConversion.swift */, 6AC893E226DB950D00F7E787 /* GCD.swift */, 6AC893E426DB950D00F7E787 /* Hashable.swift */, EC353DB92BECCF5A0026B46B /* IntegerConversion.swift */, 6AC893EC26DB950D00F7E787 /* Multiplication.swift */, EC353DBB2BECCF6A0026B46B /* PrimeTest.swift */, 6AC893F226DB950E00F7E787 /* Random.swift */, 6AC893E726DB950D00F7E787 /* Shifts.swift */, EC353DBD2BECCF770026B46B /* SquareRoot.swift */, 6AC893EF26DB950E00F7E787 /* Strideable.swift */, EC353DBF2BECCF860026B46B /* StringConversion.swift */, 6AC893EA26DB950D00F7E787 /* Subtraction.swift */, EC353DC12BECCF8F0026B46B /* WordsAndBits.swift */, 7571938D2816BFE3001C3AC0 /* CS.swift */, ); path = CS_BigInt; sourceTree = ""; }; 7507705B28D61E78004A44DC /* RSA */ = { isa = PBXGroup; children = ( 7507705C28D61E78004A44DC /* RSA.swift */, 7507705D28D61E78004A44DC /* RSA+Signature.swift */, 7507705E28D61E78004A44DC /* RSA+Cipher.swift */, ); path = RSA; sourceTree = ""; }; 7507706228D61E8B004A44DC /* PEM */ = { isa = PBXGroup; children = ( 7507706328D61E8B004A44DC /* DER.swift */, ); path = PEM; sourceTree = ""; }; 7507706528D61E97004A44DC /* ASN1 */ = { isa = PBXGroup; children = ( 7507706628D61E97004A44DC /* ASN1Scanner.swift */, 7507706728D61E97004A44DC /* ASN1Encoder.swift */, 7507706828D61E97004A44DC /* ASN1Decoder.swift */, 7507706928D61E97004A44DC /* ASN1.swift */, ); path = ASN1; sourceTree = ""; }; 75211F93207249D8004E41F8 /* CryptoSwift-TestHostApp */ = { isa = PBXGroup; children = ( 7576F64C20725BD5006688F8 /* Default-568h@2x.png */, 75211F94207249D8004E41F8 /* AppDelegate.swift */, 75211FA0207249D8004E41F8 /* Info.plist */, ); path = "CryptoSwift-TestHostApp"; sourceTree = ""; }; 7529366820683DFC00195874 /* AEAD */ = { isa = PBXGroup; children = ( 1467460E2017BB3600DF04ED /* AEAD.swift */, 7529366920683DFC00195874 /* AEADChaCha20Poly1305.swift */, ); path = AEAD; sourceTree = ""; }; 754BE44B19693E190098E6F3 = { isa = PBXGroup; children = ( 75C454012B4B6EBC00FC5020 /* PrivacyInfo.xcprivacy */, 75843E9A2072457A0050583A /* config */, 75EC52361EE8B6CA0048EB3B /* Sources */, 754BE46419693E190098E6F3 /* Tests */, 75211F93207249D8004E41F8 /* CryptoSwift-TestHostApp */, 754BE46519693E190098E6F3 /* Supporting Files */, 754BE45619693E190098E6F3 /* Products */, 24B0BBA29D734E62809E53BC /* Frameworks */, ); indentWidth = 2; sourceTree = ""; tabWidth = 2; }; 754BE45619693E190098E6F3 /* Products */ = { isa = PBXGroup; children = ( 754BE45519693E190098E6F3 /* CryptoSwift.framework */, 754BE46019693E190098E6F3 /* CryptoSwiftTests.xctest */, 75211F92207249D8004E41F8 /* CryptoSwift-TestHostApp.app */, 7595C14A2072E48C00EA1A5F /* TestsPerformance-Mac.xctest */, 7564F0602072EAEB00CA5A96 /* TestsPerformance-iOS.xctest */, ); name = Products; sourceTree = ""; }; 754BE46419693E190098E6F3 /* Tests */ = { isa = PBXGroup; children = ( 81F279DE2181F5A000449EDA /* ScryptTests.swift */, 81F279E02181F5C500449EDA /* ScryptTestsPerf.swift */, 14156CE42011422400DDCFBC /* ChaCha20Poly1305Tests.swift */, E3FD2D511D6B813C00A9F35F /* Error+Extension.swift */, 754BE46719693E190098E6F3 /* DigestTests.swift */, 7576F6EB20726319006688F8 /* DigestTestsPerf.swift */, 75100F8E19B0BC890005C5F5 /* Poly1305Tests.swift */, 758A94271A65C59200E46135 /* HMACTests.swift */, 0EE73E72204D599C00110E11 /* CMACTests.swift */, E6200E151FB9B67C00258382 /* HKDFTests.swift */, 757DA2541A4ED408002BA3EF /* AESTests.swift */, 755E0303217A756F00065FC6 /* AESCCMTests.swift */, 35F3E51D23BF9AD300A024A1 /* AESOCBTests.swift */, 7576F6EE20726422006688F8 /* AESTestsPerf.swift */, 750CC3EA1DC0CACE0096BE6E /* BlowfishTests.swift */, 757DA2581A4ED4D7002BA3EF /* ChaCha20Tests.swift */, 7576F6F020728EAB006688F8 /* ChaCha20TestsPerf.swift */, 674A736E1BF5D85B00866C5B /* RabbitTests.swift */, 7576F6F220728F00006688F8 /* RabbitTestsPerf.swift */, 755FB1D9199E347D00475437 /* ExtensionsTest.swift */, 7576F6F420729069006688F8 /* ExtensionsTestPerf.swift */, 757DA2521A4ED0A4002BA3EF /* PaddingTests.swift */, 75482EA31CB310B7001F66A5 /* PBKDF.swift */, 7576F6F6207290F8006688F8 /* PBKDFPerf.swift */, 6A7CDEEC26CD1E4C00FFB1AF /* RSATests.swift */, 5431FD592B021470001DEE77 /* SignatureVerificationTests.swift */, 75C2E76C1D55F097003D2BCA /* Access.swift */, 756BFDCA1A82B87300B9D9A4 /* Bridging.h */, ); name = Tests; path = Tests/CryptoSwiftTests; sourceTree = ""; }; 754BE46519693E190098E6F3 /* Supporting Files */ = { isa = PBXGroup; children = ( 75F4E438216C9B6900F09710 /* README.md */, 75F4E437216C9B5D00F09710 /* CHANGELOG */, ); name = "Supporting Files"; sourceTree = ""; }; 75843E9A2072457A0050583A /* config */ = { isa = PBXGroup; children = ( 75211FAF20724A10004E41F8 /* CryptoSwift-Debug.xcconfig */, 75211FAC20724A0F004E41F8 /* CryptoSwift-Release.xcconfig */, 75211FA820724A0F004E41F8 /* CryptoSwift-Shared.xcconfig */, 75211FB420724A10004E41F8 /* CryptoSwift-Test.xcconfig */, 75211FA520724A0F004E41F8 /* CryptoSwift-TestHostApp-Test.xcconfig */, 75211FA920724A0F004E41F8 /* CryptoSwift-TestHostApp-Shared.xcconfig */, 75211FB020724A10004E41F8 /* Project-Debug.xcconfig */, 75211FAA20724A0F004E41F8 /* Project-Release.xcconfig */, 75211FB220724A10004E41F8 /* Project-Shared.xcconfig */, 75211FAE20724A10004E41F8 /* Tests-Shared.xcconfig */, 75211FB120724A10004E41F8 /* Tests-Test.xcconfig */, ); path = config; sourceTree = ""; }; 75EC52361EE8B6CA0048EB3B /* Sources */ = { isa = PBXGroup; children = ( 75EC52371EE8B6CA0048EB3B /* CryptoSwift */, 75EC527A1EE8B6CA0048EB3B /* CryptoSwift.h */, ); path = Sources; sourceTree = ""; }; 75EC52371EE8B6CA0048EB3B /* CryptoSwift */ = { isa = PBXGroup; children = ( 7507706528D61E97004A44DC /* ASN1 */, 7507706228D61E8B004A44DC /* PEM */, 7507705B28D61E78004A44DC /* RSA */, 0AF023D4230F2B0F008E4E68 /* ISO78164Padding.swift */, 42012782267A6F1C00F82506 /* ISO10126Padding.swift */, 7529366820683DFC00195874 /* AEAD */, 75EC52381EE8B6CA0048EB3B /* AES.swift */, 751EE9771F93996100161FFC /* AES.Cryptors.swift */, 75EC52391EE8B6CA0048EB3B /* Array+Extension.swift */, 75EC523A1EE8B6CA0048EB3B /* Authenticator.swift */, 75EC523B1EE8B6CA0048EB3B /* BatchedCollection.swift */, 6AC893DF26DB94F700F7E787 /* CS_BigInt */, 75EC523C1EE8B6CA0048EB3B /* Bit.swift */, 75EC523D1EE8B6CA0048EB3B /* BlockCipher.swift */, 75EC523E1EE8B6CA0048EB3B /* BlockMode */, 75EC52491EE8B6CA0048EB3B /* Blowfish.swift */, 75EC524A1EE8B6CA0048EB3B /* ChaCha20.swift */, 75EC524B1EE8B6CA0048EB3B /* Checksum.swift */, 75EC524C1EE8B6CA0048EB3B /* Cipher.swift */, 0EE73E70204D598100110E11 /* CMAC.swift */, 75F4E435216C98DE00F09710 /* CBCMAC.swift */, 75EC524D1EE8B6CA0048EB3B /* Collection+Extension.swift */, 75EC524E1EE8B6CA0048EB3B /* Cryptors.swift */, 75EC52501EE8B6CA0048EB3B /* Digest.swift */, 75EC52511EE8B6CA0048EB3B /* DigestType.swift */, 75EC52521EE8B6CA0048EB3B /* Foundation */, 75EC525C1EE8B6CA0048EB3B /* Generics.swift */, E6200E131FB9A7AE00258382 /* HKDF.swift */, 75EC525D1EE8B6CA0048EB3B /* HMAC.swift */, 75EC52611EE8B6CA0048EB3B /* MD5.swift */, 75EC52621EE8B6CA0048EB3B /* NoPadding.swift */, 75EC52631EE8B6CA0048EB3B /* Operators.swift */, 75EC52641EE8B6CA0048EB3B /* Padding.swift */, 75EC52651EE8B6CA0048EB3B /* PKCS */, 75EC526A1EE8B6CA0048EB3B /* Poly1305.swift */, 75EC526B1EE8B6CA0048EB3B /* Rabbit.swift */, 75EC526C1EE8B6CA0048EB3B /* Cryptor.swift */, 75EC526E1EE8B6CA0048EB3B /* SecureBytes.swift */, 81F279DC2181F58300449EDA /* Scrypt.swift */, 75EC526F1EE8B6CA0048EB3B /* SHA1.swift */, 75EC52701EE8B6CA0048EB3B /* SHA2.swift */, 75EC52711EE8B6CA0048EB3B /* SHA3.swift */, 75EC52721EE8B6CA0048EB3B /* String+Extension.swift */, 75EC525F1EE8B6CA0048EB3B /* Int+Extension.swift */, 75EC52761EE8B6CA0048EB3B /* UInt8+Extension.swift */, 75EC52731EE8B6CA0048EB3B /* UInt16+Extension.swift */, 75EC52741EE8B6CA0048EB3B /* UInt32+Extension.swift */, 75EC52751EE8B6CA0048EB3B /* UInt64+Extension.swift */, 75D7AF37208BFB1600D22BEB /* UInt128.swift */, 75EC52771EE8B6CA0048EB3B /* Updatable.swift */, 75EC52781EE8B6CA0048EB3B /* Utils.swift */, 75EC52791EE8B6CA0048EB3B /* ZeroPadding.swift */, 754310432050111A003FB1DF /* CompactMap.swift */, 75B3ED76210F9DF7005D4ADA /* BlockDecryptor.swift */, 75B3ED78210FA016005D4ADA /* BlockEncryptor.swift */, 753674062175D012003E32A6 /* StreamDecryptor.swift */, 756A64C52111083B00BE8805 /* StreamEncryptor.swift */, 7507707028D61ED5004A44DC /* Signature.swift */, ); path = CryptoSwift; sourceTree = ""; }; 75EC523E1EE8B6CA0048EB3B /* BlockMode */ = { isa = PBXGroup; children = ( 75EC523F1EE8B6CA0048EB3B /* BlockMode.swift */, 75EC52401EE8B6CA0048EB3B /* BlockModeOptions.swift */, 75EC52411EE8B6CA0048EB3B /* CipherModeWorker.swift */, 75EC52421EE8B6CA0048EB3B /* CBC.swift */, 75EC52431EE8B6CA0048EB3B /* CFB.swift */, 75EC52441EE8B6CA0048EB3B /* CTR.swift */, 7523742C2083C61C0016D662 /* GCM.swift */, 75F4E433216C93EF00F09710 /* CCM.swift */, 75EC52451EE8B6CA0048EB3B /* ECB.swift */, 75EC52461EE8B6CA0048EB3B /* OFB.swift */, 75EC52471EE8B6CA0048EB3B /* PCBC.swift */, 35F3E51B23BF9A6700A024A1 /* OCB.swift */, ); path = BlockMode; sourceTree = ""; }; 75EC52521EE8B6CA0048EB3B /* Foundation */ = { isa = PBXGroup; children = ( 75EC52531EE8B6CA0048EB3B /* AES+Foundation.swift */, 75EC52541EE8B6CA0048EB3B /* Blowfish+Foundation.swift */, 75EC52551EE8B6CA0048EB3B /* ChaCha20+Foundation.swift */, 75EC52561EE8B6CA0048EB3B /* Array+Foundation.swift */, 75EC52571EE8B6CA0048EB3B /* Data+Extension.swift */, 75EC52581EE8B6CA0048EB3B /* HMAC+Foundation.swift */, 75EC52591EE8B6CA0048EB3B /* Rabbit+Foundation.swift */, 75EC525A1EE8B6CA0048EB3B /* String+FoundationExtension.swift */, 75EC525B1EE8B6CA0048EB3B /* Utils+Foundation.swift */, ); path = Foundation; sourceTree = ""; }; 75EC52651EE8B6CA0048EB3B /* PKCS */ = { isa = PBXGroup; children = ( 75EC52691EE8B6CA0048EB3B /* PKCS7Padding.swift */, 75EC52661EE8B6CA0048EB3B /* PBKDF1.swift */, 75EC52671EE8B6CA0048EB3B /* PBKDF2.swift */, 7507706E28D61EBA004A44DC /* PKCS1v15.swift */, 75EC52681EE8B6CA0048EB3B /* PKCS5.swift */, 750509981F6BEF2A00394A1B /* PKCS7.swift */, ); path = PKCS; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 754BE45219693E190098E6F3 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 75EC527B1EE8B73A0048EB3B /* CryptoSwift.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 75211F91207249D8004E41F8 /* CryptoSwift-TestHostApp */ = { isa = PBXNativeTarget; buildConfigurationList = 75211FA4207249D8004E41F8 /* Build configuration list for PBXNativeTarget "CryptoSwift-TestHostApp" */; buildPhases = ( 75211F8E207249D8004E41F8 /* Sources */, 75211F8F207249D8004E41F8 /* Frameworks */, 75211F90207249D8004E41F8 /* Resources */, 7564F0682072ED7000CA5A96 /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( 7564F0672072ED7000CA5A96 /* PBXTargetDependency */, ); name = "CryptoSwift-TestHostApp"; productName = "CryptoSwift-TestHostApp"; productReference = 75211F92207249D8004E41F8 /* CryptoSwift-TestHostApp.app */; productType = "com.apple.product-type.application"; }; 754BE45419693E190098E6F3 /* CryptoSwift */ = { isa = PBXNativeTarget; buildConfigurationList = 754BE46B19693E190098E6F3 /* Build configuration list for PBXNativeTarget "CryptoSwift" */; buildPhases = ( 754BE45219693E190098E6F3 /* Headers */, 754BE45019693E190098E6F3 /* Sources */, 754BE45119693E190098E6F3 /* Frameworks */, 754BE45319693E190098E6F3 /* Resources */, 75B601E0197D69770009B53D /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = CryptoSwift; packageProductDependencies = ( ); productName = CryptoSwift; productReference = 754BE45519693E190098E6F3 /* CryptoSwift.framework */; productType = "com.apple.product-type.framework"; }; 754BE45F19693E190098E6F3 /* CryptoSwiftTests */ = { isa = PBXNativeTarget; buildConfigurationList = 754BE46E19693E190098E6F3 /* Build configuration list for PBXNativeTarget "CryptoSwiftTests" */; buildPhases = ( 754BE45C19693E190098E6F3 /* Sources */, 754BE45D19693E190098E6F3 /* Frameworks */, 754BE45E19693E190098E6F3 /* Resources */, ); buildRules = ( ); dependencies = ( 75B601E4197D69EB0009B53D /* PBXTargetDependency */, 75F9482220BDDF9900956311 /* PBXTargetDependency */, ); name = CryptoSwiftTests; productName = Tests; productReference = 754BE46019693E190098E6F3 /* CryptoSwiftTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 7564F04E2072EAEB00CA5A96 /* TestsPerformance-iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 7564F05C2072EAEB00CA5A96 /* Build configuration list for PBXNativeTarget "TestsPerformance-iOS" */; buildPhases = ( 7564F0512072EAEB00CA5A96 /* Sources */, 7564F0592072EAEB00CA5A96 /* Frameworks */, 7564F05B2072EAEB00CA5A96 /* Resources */, ); buildRules = ( ); dependencies = ( 7564F04F2072EAEB00CA5A96 /* PBXTargetDependency */, 7564F0622072EB5D00CA5A96 /* PBXTargetDependency */, ); name = "TestsPerformance-iOS"; productName = TestsPerformance; productReference = 7564F0602072EAEB00CA5A96 /* TestsPerformance-iOS.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 7595C1492072E48C00EA1A5F /* TestsPerformance-Mac */ = { isa = PBXNativeTarget; buildConfigurationList = 7595C1522072E48C00EA1A5F /* Build configuration list for PBXNativeTarget "TestsPerformance-Mac" */; buildPhases = ( 7595C1462072E48C00EA1A5F /* Sources */, 7595C1472072E48C00EA1A5F /* Frameworks */, 7595C1482072E48C00EA1A5F /* Resources */, ); buildRules = ( ); dependencies = ( 7595C15F2072E64000EA1A5F /* PBXTargetDependency */, ); name = "TestsPerformance-Mac"; productName = TestsPerformance; productReference = 7595C14A2072E48C00EA1A5F /* TestsPerformance-Mac.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 754BE44C19693E190098E6F3 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0930; LastUpgradeCheck = 1400; ORGANIZATIONNAME = "Marcin Krzyzanowski"; TargetAttributes = { 75211F91207249D8004E41F8 = { CreatedOnToolsVersion = 9.3; LastSwiftMigration = 1020; ProvisioningStyle = Manual; }; 754BE45419693E190098E6F3 = { CreatedOnToolsVersion = 6.0; LastSwiftMigration = 1020; ProvisioningStyle = Manual; }; 754BE45F19693E190098E6F3 = { CreatedOnToolsVersion = 6.0; LastSwiftMigration = 1020; ProvisioningStyle = Manual; }; 7564F04E2072EAEB00CA5A96 = { LastSwiftMigration = 1020; ProvisioningStyle = Manual; TestTargetID = 75211F91207249D8004E41F8; }; 7595C1492072E48C00EA1A5F = { CreatedOnToolsVersion = 9.3; LastSwiftMigration = 1020; ProvisioningStyle = Manual; }; }; }; buildConfigurationList = 754BE44F19693E190098E6F3 /* Build configuration list for PBXProject "CryptoSwift" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 754BE44B19693E190098E6F3; packageReferences = ( ); productRefGroup = 754BE45619693E190098E6F3 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 754BE45419693E190098E6F3 /* CryptoSwift */, 75211F91207249D8004E41F8 /* CryptoSwift-TestHostApp */, 754BE45F19693E190098E6F3 /* CryptoSwiftTests */, 7595C1492072E48C00EA1A5F /* TestsPerformance-Mac */, 7564F04E2072EAEB00CA5A96 /* TestsPerformance-iOS */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 75211F90207249D8004E41F8 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 755BA296235387700039CAB5 /* Default-568h@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 754BE45319693E190098E6F3 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 754BE45E19693E190098E6F3 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 7564F05B2072EAEB00CA5A96 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 7595C1482072E48C00EA1A5F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 75211F8E207249D8004E41F8 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 75211F95207249D8004E41F8 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 754BE45019693E190098E6F3 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 7507705F28D61E78004A44DC /* RSA.swift in Sources */, 42012783267A6F1C00F82506 /* ISO10126Padding.swift in Sources */, EC353DB42BECCEFD0026B46B /* BitwiseOps.swift in Sources */, 6AC8940226DB950F00F7E787 /* Multiplication.swift in Sources */, 0AF023D5230F2B0F008E4E68 /* ISO78164Padding.swift in Sources */, EC353DBA2BECCF5A0026B46B /* IntegerConversion.swift in Sources */, 75EC52861EE8B8170048EB3B /* CFB.swift in Sources */, 75EC52901EE8B81A0048EB3B /* Collection+Extension.swift in Sources */, EC353DBE2BECCF770026B46B /* SquareRoot.swift in Sources */, EC353DC02BECCF860026B46B /* StringConversion.swift in Sources */, 0EE73E71204D598100110E11 /* CMAC.swift in Sources */, EC353DBC2BECCF6A0026B46B /* PrimeTest.swift in Sources */, 7523742D2083C61D0016D662 /* GCM.swift in Sources */, 75F4E436216C98DE00F09710 /* CBCMAC.swift in Sources */, 752BED9F208C135700FC4743 /* AES+Foundation.swift in Sources */, E6200E141FB9A7AE00258382 /* HKDF.swift in Sources */, 75EC529F1EE8B8230048EB3B /* HMAC.swift in Sources */, 75EC52B91EE8B83D0048EB3B /* ZeroPadding.swift in Sources */, 7507706428D61E8B004A44DC /* DER.swift in Sources */, 7529366A20683DFC00195874 /* AEADChaCha20Poly1305.swift in Sources */, 6AC893FA26DB950F00F7E787 /* Hashable.swift in Sources */, 75EC529E1EE8B8230048EB3B /* Generics.swift in Sources */, 75EC52AA1EE8B83D0048EB3B /* Poly1305.swift in Sources */, 75EC52AC1EE8B83D0048EB3B /* Cryptor.swift in Sources */, 75EC52821EE8B8170048EB3B /* BlockMode.swift in Sources */, 75EC52AE1EE8B83D0048EB3B /* SecureBytes.swift in Sources */, 6AC893FC26DB950F00F7E787 /* Codable.swift in Sources */, 75EC528F1EE8B81A0048EB3B /* Cipher.swift in Sources */, 75B3ED79210FA016005D4ADA /* BlockEncryptor.swift in Sources */, 75EC52A01EE8B8290048EB3B /* Int+Extension.swift in Sources */, 7507706028D61E78004A44DC /* RSA+Signature.swift in Sources */, 75EC52B01EE8B83D0048EB3B /* SHA2.swift in Sources */, 6AC893F626DB950F00F7E787 /* Addition.swift in Sources */, 752BED9D208C120D00FC4743 /* Blowfish+Foundation.swift in Sources */, 75EC52B71EE8B83D0048EB3B /* Updatable.swift in Sources */, 75EC528E1EE8B81A0048EB3B /* Checksum.swift in Sources */, 754310442050111A003FB1DF /* CompactMap.swift in Sources */, 7507706B28D61E97004A44DC /* ASN1Encoder.swift in Sources */, 75EC52811EE8B8130048EB3B /* BlockCipher.swift in Sources */, 75EC52941EE8B81A0048EB3B /* DigestType.swift in Sources */, 75EC529B1EE8B8200048EB3B /* Rabbit+Foundation.swift in Sources */, 6AC893F926DB950F00F7E787 /* Comparable.swift in Sources */, 756A64C62111083B00BE8805 /* StreamEncryptor.swift in Sources */, 6AC8940726DB950F00F7E787 /* Exponentiation.swift in Sources */, 6AC8940026DB950F00F7E787 /* Subtraction.swift in Sources */, 75EC52A61EE8B8390048EB3B /* PBKDF1.swift in Sources */, 75EC52B41EE8B83D0048EB3B /* UInt32+Extension.swift in Sources */, 6AC8940526DB950F00F7E787 /* Strideable.swift in Sources */, 75EC52911EE8B81A0048EB3B /* Cryptors.swift in Sources */, 75EC52881EE8B8170048EB3B /* ECB.swift in Sources */, 75EC52841EE8B8170048EB3B /* CipherModeWorker.swift in Sources */, 75EC52A41EE8B8290048EB3B /* Operators.swift in Sources */, 75EC529A1EE8B8200048EB3B /* HMAC+Foundation.swift in Sources */, 6AC8940826DB950F00F7E787 /* Random.swift in Sources */, 75EC52B21EE8B83D0048EB3B /* String+Extension.swift in Sources */, 750509991F6BEF2A00394A1B /* PKCS7.swift in Sources */, 7507706C28D61E97004A44DC /* ASN1Decoder.swift in Sources */, 75EC52B51EE8B83D0048EB3B /* UInt64+Extension.swift in Sources */, EC353DB62BECCF3A0026B46B /* DataConversion.swift in Sources */, 7507707128D61ED5004A44DC /* Signature.swift in Sources */, 75EC52AF1EE8B83D0048EB3B /* SHA1.swift in Sources */, 75EC52801EE8B8130048EB3B /* Bit.swift in Sources */, 7507706D28D61E97004A44DC /* ASN1.swift in Sources */, 75EC52971EE8B8200048EB3B /* ChaCha20+Foundation.swift in Sources */, 75F4E434216C93EF00F09710 /* CCM.swift in Sources */, 75EC52871EE8B8170048EB3B /* CTR.swift in Sources */, 6AC893FD26DB950F00F7E787 /* Shifts.swift in Sources */, 75EC52A21EE8B8290048EB3B /* MD5.swift in Sources */, 75EC527C1EE8B8130048EB3B /* AES.swift in Sources */, 752BED9E208C121000FC4743 /* Blowfish.swift in Sources */, 75EC52A91EE8B83D0048EB3B /* PKCS7Padding.swift in Sources */, 75EC52A51EE8B8290048EB3B /* Padding.swift in Sources */, 7507706128D61E78004A44DC /* RSA+Cipher.swift in Sources */, 6AC8940A26DB950F00F7E787 /* BigUInt.swift in Sources */, 75EC527F1EE8B8130048EB3B /* BatchedCollection.swift in Sources */, 75EC52991EE8B8200048EB3B /* Data+Extension.swift in Sources */, 75EC52B61EE8B83D0048EB3B /* UInt8+Extension.swift in Sources */, 75EC52891EE8B8170048EB3B /* OFB.swift in Sources */, 75EC52831EE8B8170048EB3B /* BlockModeOptions.swift in Sources */, 753674072175D012003E32A6 /* StreamDecryptor.swift in Sources */, 6AC8940626DB950F00F7E787 /* BigInt.swift in Sources */, EC353DC22BECCF8F0026B46B /* WordsAndBits.swift in Sources */, 751EE9781F93996100161FFC /* AES.Cryptors.swift in Sources */, 75EC527D1EE8B8130048EB3B /* Array+Extension.swift in Sources */, 75D7AF38208BFB1600D22BEB /* UInt128.swift in Sources */, 7571938E2816BFE3001C3AC0 /* CS.swift in Sources */, 75EC52B31EE8B83D0048EB3B /* UInt16+Extension.swift in Sources */, 75EC52A81EE8B8390048EB3B /* PKCS5.swift in Sources */, 1467460F2017BB3600DF04ED /* AEAD.swift in Sources */, 35F3E51C23BF9A6700A024A1 /* OCB.swift in Sources */, 6AC8940B26DB950F00F7E787 /* Division.swift in Sources */, 75EC528A1EE8B8170048EB3B /* PCBC.swift in Sources */, 75EC528D1EE8B81A0048EB3B /* ChaCha20.swift in Sources */, 75EC52851EE8B8170048EB3B /* CBC.swift in Sources */, 75EC52A71EE8B8390048EB3B /* PBKDF2.swift in Sources */, 75EC529D1EE8B8200048EB3B /* Utils+Foundation.swift in Sources */, 75EC527E1EE8B8130048EB3B /* Authenticator.swift in Sources */, 7507706A28D61E97004A44DC /* ASN1Scanner.swift in Sources */, 75EC52AB1EE8B83D0048EB3B /* Rabbit.swift in Sources */, 75B3ED77210F9DF7005D4ADA /* BlockDecryptor.swift in Sources */, 7507706F28D61EBA004A44DC /* PKCS1v15.swift in Sources */, 75EC529C1EE8B8200048EB3B /* String+FoundationExtension.swift in Sources */, 75EC52B81EE8B83D0048EB3B /* Utils.swift in Sources */, 75EC52981EE8B8200048EB3B /* Array+Foundation.swift in Sources */, 75EC52B11EE8B83D0048EB3B /* SHA3.swift in Sources */, 75EC52A31EE8B8290048EB3B /* NoPadding.swift in Sources */, EC353DB82BECCF4B0026B46B /* FloatingPointConversion.swift in Sources */, 6AC893F826DB950F00F7E787 /* GCD.swift in Sources */, 81F279DD2181F58300449EDA /* Scrypt.swift in Sources */, 75EC52931EE8B81A0048EB3B /* Digest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 754BE45C19693E190098E6F3 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 751AA0F3255F4EB600D4719E /* AESOCBTests.swift in Sources */, 75C2E76D1D55F097003D2BCA /* Access.swift in Sources */, 75482EA41CB310B7001F66A5 /* PBKDF.swift in Sources */, 758A94291A65C67400E46135 /* HMACTests.swift in Sources */, 75100F8F19B0BC890005C5F5 /* Poly1305Tests.swift in Sources */, E6200E171FB9B68C00258382 /* HKDFTests.swift in Sources */, 754BE46819693E190098E6F3 /* DigestTests.swift in Sources */, E3FD2D531D6B81CE00A9F35F /* Error+Extension.swift in Sources */, 757DA2591A4ED4D7002BA3EF /* ChaCha20Tests.swift in Sources */, 755FB1DA199E347D00475437 /* ExtensionsTest.swift in Sources */, 81F279DF2181F5A000449EDA /* ScryptTests.swift in Sources */, 674A736F1BF5D85B00866C5B /* RabbitTests.swift in Sources */, 0EE73E74204D59C200110E11 /* CMACTests.swift in Sources */, 6A7CDEED26CD1E4C00FFB1AF /* RSATests.swift in Sources */, 750CC3EB1DC0CACE0096BE6E /* BlowfishTests.swift in Sources */, 757DA2531A4ED0A4002BA3EF /* PaddingTests.swift in Sources */, 14156CE52011422400DDCFBC /* ChaCha20Poly1305Tests.swift in Sources */, 757DA2551A4ED408002BA3EF /* AESTests.swift in Sources */, 5431FD5B2B021476001DEE77 /* SignatureVerificationTests.swift in Sources */, 7594CCBC217A76DC0055C95D /* AESCCMTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 7564F0512072EAEB00CA5A96 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 7564F0522072EAEB00CA5A96 /* PBKDFPerf.swift in Sources */, 7564F0532072EAEB00CA5A96 /* ChaCha20TestsPerf.swift in Sources */, 7564F0542072EAEB00CA5A96 /* RabbitTestsPerf.swift in Sources */, 7564F0552072EAEB00CA5A96 /* ExtensionsTestPerf.swift in Sources */, 7564F0562072EAEB00CA5A96 /* DigestTestsPerf.swift in Sources */, 81F279E22181F5C500449EDA /* ScryptTestsPerf.swift in Sources */, 7564F0582072EAEB00CA5A96 /* AESTestsPerf.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 7595C1462072E48C00EA1A5F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 7595C15D2072E5B900EA1A5F /* PBKDFPerf.swift in Sources */, 7595C15A2072E5B900EA1A5F /* ChaCha20TestsPerf.swift in Sources */, 7595C15B2072E5B900EA1A5F /* RabbitTestsPerf.swift in Sources */, 7595C15C2072E5B900EA1A5F /* ExtensionsTestPerf.swift in Sources */, 7595C1582072E5B900EA1A5F /* DigestTestsPerf.swift in Sources */, 81F279E12181F5C500449EDA /* ScryptTestsPerf.swift in Sources */, 7595C1592072E5B900EA1A5F /* AESTestsPerf.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 7564F04F2072EAEB00CA5A96 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 754BE45419693E190098E6F3 /* CryptoSwift */; targetProxy = 7564F0502072EAEB00CA5A96 /* PBXContainerItemProxy */; }; 7564F0622072EB5D00CA5A96 /* PBXTargetDependency */ = { isa = PBXTargetDependency; platformFilter = ios; target = 75211F91207249D8004E41F8 /* CryptoSwift-TestHostApp */; targetProxy = 7564F0612072EB5D00CA5A96 /* PBXContainerItemProxy */; }; 7564F0672072ED7000CA5A96 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 754BE45419693E190098E6F3 /* CryptoSwift */; targetProxy = 7564F0662072ED7000CA5A96 /* PBXContainerItemProxy */; }; 7595C15F2072E64000EA1A5F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 754BE45419693E190098E6F3 /* CryptoSwift */; targetProxy = 7595C15E2072E64000EA1A5F /* PBXContainerItemProxy */; }; 75B601E4197D69EB0009B53D /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 754BE45419693E190098E6F3 /* CryptoSwift */; targetProxy = 75B601E3197D69EB0009B53D /* PBXContainerItemProxy */; }; 75F9482220BDDF9900956311 /* PBXTargetDependency */ = { isa = PBXTargetDependency; platformFilter = ios; target = 75211F91207249D8004E41F8 /* CryptoSwift-TestHostApp */; targetProxy = 75F9482120BDDF9900956311 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 75211FA1207249D8004E41F8 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { }; name = Debug; }; 75211FA2207249D8004E41F8 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { }; name = Release; }; 75211FA3207249D8004E41F8 /* Test */ = { isa = XCBuildConfiguration; baseConfigurationReference = 75211FA520724A0F004E41F8 /* CryptoSwift-TestHostApp-Test.xcconfig */; buildSettings = { }; name = Test; }; 754BE46919693E190098E6F3 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 75211FB020724A10004E41F8 /* Project-Debug.xcconfig */; buildSettings = { }; name = Debug; }; 754BE46A19693E190098E6F3 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 75211FAA20724A0F004E41F8 /* Project-Release.xcconfig */; buildSettings = { }; name = Release; }; 754BE46C19693E190098E6F3 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 75211FAF20724A10004E41F8 /* CryptoSwift-Debug.xcconfig */; buildSettings = { }; name = Debug; }; 754BE46D19693E190098E6F3 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 75211FAC20724A0F004E41F8 /* CryptoSwift-Release.xcconfig */; buildSettings = { }; name = Release; }; 754BE46F19693E190098E6F3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { }; name = Debug; }; 754BE47019693E190098E6F3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { }; name = Release; }; 7564F05D2072EAEB00CA5A96 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { SDKROOT = iphoneos; }; name = Debug; }; 7564F05E2072EAEB00CA5A96 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { SDKROOT = iphoneos; }; name = Release; }; 7564F05F2072EAEB00CA5A96 /* Test */ = { isa = XCBuildConfiguration; baseConfigurationReference = 75211FB120724A10004E41F8 /* Tests-Test.xcconfig */; buildSettings = { SDKROOT = iphoneos; }; name = Test; }; 756B66AA1F6AAFDB00DEC41C /* Test */ = { isa = XCBuildConfiguration; baseConfigurationReference = 75211FB220724A10004E41F8 /* Project-Shared.xcconfig */; buildSettings = { }; name = Test; }; 756B66AB1F6AAFDB00DEC41C /* Test */ = { isa = XCBuildConfiguration; baseConfigurationReference = 75211FB420724A10004E41F8 /* CryptoSwift-Test.xcconfig */; buildSettings = { }; name = Test; }; 756B66AC1F6AAFDB00DEC41C /* Test */ = { isa = XCBuildConfiguration; baseConfigurationReference = 75211FB120724A10004E41F8 /* Tests-Test.xcconfig */; buildSettings = { }; name = Test; }; 7595C14F2072E48C00EA1A5F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { }; name = Debug; }; 7595C1502072E48C00EA1A5F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { }; name = Release; }; 7595C1512072E48C00EA1A5F /* Test */ = { isa = XCBuildConfiguration; baseConfigurationReference = 75211FB120724A10004E41F8 /* Tests-Test.xcconfig */; buildSettings = { }; name = Test; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 75211FA4207249D8004E41F8 /* Build configuration list for PBXNativeTarget "CryptoSwift-TestHostApp" */ = { isa = XCConfigurationList; buildConfigurations = ( 75211FA1207249D8004E41F8 /* Debug */, 75211FA2207249D8004E41F8 /* Release */, 75211FA3207249D8004E41F8 /* Test */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 754BE44F19693E190098E6F3 /* Build configuration list for PBXProject "CryptoSwift" */ = { isa = XCConfigurationList; buildConfigurations = ( 754BE46919693E190098E6F3 /* Debug */, 754BE46A19693E190098E6F3 /* Release */, 756B66AA1F6AAFDB00DEC41C /* Test */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 754BE46B19693E190098E6F3 /* Build configuration list for PBXNativeTarget "CryptoSwift" */ = { isa = XCConfigurationList; buildConfigurations = ( 754BE46C19693E190098E6F3 /* Debug */, 754BE46D19693E190098E6F3 /* Release */, 756B66AB1F6AAFDB00DEC41C /* Test */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 754BE46E19693E190098E6F3 /* Build configuration list for PBXNativeTarget "CryptoSwiftTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 754BE46F19693E190098E6F3 /* Debug */, 754BE47019693E190098E6F3 /* Release */, 756B66AC1F6AAFDB00DEC41C /* Test */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 7564F05C2072EAEB00CA5A96 /* Build configuration list for PBXNativeTarget "TestsPerformance-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 7564F05D2072EAEB00CA5A96 /* Debug */, 7564F05E2072EAEB00CA5A96 /* Release */, 7564F05F2072EAEB00CA5A96 /* Test */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 7595C1522072E48C00EA1A5F /* Build configuration list for PBXNativeTarget "TestsPerformance-Mac" */ = { isa = XCConfigurationList; buildConfigurations = ( 7595C14F2072E48C00EA1A5F /* Debug */, 7595C1502072E48C00EA1A5F /* Release */, 7595C1512072E48C00EA1A5F /* Test */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 754BE44C19693E190098E6F3 /* Project object */; } ================================================ FILE: CryptoSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: CryptoSwift.xcodeproj/project.xcworkspace/xcshareddata/CryptoSwift.xcscmblueprint ================================================ ================================================ FILE: CryptoSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: CryptoSwift.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings ================================================ IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded ================================================ FILE: CryptoSwift.xcodeproj/xcshareddata/IDETemplateMacros.plist ================================================ FILEHEADER // CryptoSwift // // Copyright (C) 2014-__YEAR__ Marcin Krzyżanowski <marcin@krzyzanowskim.com> // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // ================================================ FILE: CryptoSwift.xcodeproj/xcshareddata/xcschemes/CryptoSwift-TestHostApp.xcscheme ================================================ ================================================ FILE: CryptoSwift.xcodeproj/xcshareddata/xcschemes/CryptoSwift.xcscheme ================================================ ================================================ FILE: CryptoSwift.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme ================================================ ================================================ FILE: CryptoSwift.xcodeproj/xcshareddata/xcschemes/TestsPerformance-Mac.xcscheme ================================================ ================================================ FILE: CryptoSwift.xcodeproj/xcshareddata/xcschemes/TestsPerformance-iOS.xcscheme ================================================ ================================================ FILE: Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString $(MARKETING_VERSION) CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ FILE: LICENSE ================================================ Copyright (C) 2014-3099 Marcin Krzyżanowski This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - This notice may not be removed or altered from any source or binary distribution. - Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the "Marcin Krzyzanowski" (http://krzyzanowskim.com/).' ================================================ FILE: Makefile ================================================ .PHONY: frameworks CWD := $(abspath $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))) frameworks: $(CWD)/scripts/build-framework.sh @echo "Framework built in $(CWD)/CryptoSwift.xcframework" all: frameworks ================================================ FILE: Package.swift ================================================ // swift-tools-version:5.6 import PackageDescription let package = Package( name: "CryptoSwift", platforms: [ .macOS(.v10_13), .macCatalyst(.v13), .iOS(.v11), .tvOS(.v11), .watchOS(.v4), .custom("visionos", versionString: "1.0") ], products: [ .library( name: "CryptoSwift", targets: ["CryptoSwift"] ) ], targets: [ .target(name: "CryptoSwift", resources: [.copy("PrivacyInfo.xcprivacy")]), .testTarget(name: "CryptoSwiftTests", dependencies: ["CryptoSwift"]) ], swiftLanguageVersions: [.v5] ) ================================================ FILE: README.md ================================================ [![Platform](https://img.shields.io/badge/Platforms-iOS%20%7C%20Android%20%7C%20macOS%20%7C%20watchOS%20%7C%20tvOS%20%7C%20Linux-4E4E4E.svg?colorA=28a745)](#installation) [![Swift support](https://img.shields.io/badge/Swift-3.1%20%7C%203.2%20%7C%204.0%20%7C%204.1%20%7C%204.2%20%7C%205.0%20%7C%206.2-lightgrey.svg?colorA=28a745&colorB=4E4E4E)](#swift-versions-support) [![Swift Package Manager compatible](https://img.shields.io/badge/SPM-compatible-brightgreen.svg?style=flat&colorA=28a745&&colorB=4E4E4E)](https://github.com/swiftlang/swift-package-manager) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-brightgreen.svg?style=flat&colorA=28a745&&colorB=4E4E4E)](https://github.com/Carthage/Carthage) [![CocoaPods Deprecated](https://img.shields.io/cocoapods/v/CryptoSwift.svg?style=flat&label=CocoaPods&colorA=red&&colorB=4E4E4E)](https://cocoapods.org/pods/CryptoSwift) # CryptoSwift Crypto related functions and helpers for [Swift](https://swift.org) implemented in Swift. ([#PureSwift](https://twitter.com/hashtag/pureswift)) **Note**: The `main` branch follows the latest currently released **version of Swift**. If you need an earlier version for an older version of Swift, specify its version in your `Podfile` or use the code on the branch for that version. Older branches are unsupported. Check [versions](#swift-versions-support) for details. --- [Requirements](#requirements) | [Features](#features) | [Contribution](#contribution) | [Installation](#installation) | [Swift versions](#swift-versions-support) | [How-to](#how-to) | [Author](#author) | [License](#license) | [Changelog](#changelog) ### Support & Sponsors The financial sustainability of the project is possible thanks to the ongoing contributions from our [GitHub Sponsors](https://github.com/sponsors/krzyzanowskim) ### Premium Sponsors [Emerge Tools](https://www.emergetools.com/) is a suite of revolutionary products designed to supercharge mobile apps and the teams that build them. [www.emergetools.com/](https://www.emergetools.com) ## Requirements Good mood ## Features - Easy to use - Convenient extensions for String and Data - Support for incremental updates (stream, ...) - iOS, Android, macOS, AppleTV, watchOS, Linux support #### Hash (Digest) [MD5](https://tools.ietf.org/html/rfc1321) | [SHA1](https://tools.ietf.org/html/rfc3174) | [SHA2-224](https://tools.ietf.org/html/rfc6234) | [SHA2-256](https://tools.ietf.org/html/rfc6234) | [SHA2-384](https://tools.ietf.org/html/rfc6234) | [SHA2-512](https://tools.ietf.org/html/rfc6234) | [SHA3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) #### Cyclic Redundancy Check (CRC) [CRC32](https://en.wikipedia.org/wiki/Cyclic_redundancy_check) | [CRC32C](https://en.wikipedia.org/wiki/Cyclic_redundancy_check) | [CRC16](https://en.wikipedia.org/wiki/Cyclic_redundancy_check) #### Cipher [AES-128, AES-192, AES-256](http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf) | [ChaCha20](http://cr.yp.to/chacha/chacha-20080128.pdf) | [XChaCha20](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha) | [Rabbit](https://tools.ietf.org/html/rfc4503) | [Blowfish](https://www.schneier.com/academic/blowfish/) #### RSA (public-key encryption algorithm) [Encryption, Signature](https://github.com/krzyzanowskim/CryptoSwift#rsa) #### Message authenticators [Poly1305](https://cr.yp.to/mac/poly1305-20050329.pdf) | [HMAC (MD5, SHA1, SHA256)](https://www.ietf.org/rfc/rfc2104.txt) | [CMAC](https://tools.ietf.org/html/rfc4493) | [CBC-MAC](https://en.wikipedia.org/wiki/CBC-MAC) #### Cipher mode of operation - Electronic codebook ([ECB](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29)) - Cipher-block chaining ([CBC](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29)) - Propagating Cipher Block Chaining ([PCBC](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Propagating_Cipher_Block_Chaining_.28PCBC.29)) - Cipher feedback ([CFB](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29)) - Output Feedback ([OFB](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_Feedback_.28OFB.29)) - Counter Mode ([CTR](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29)) - Galois/Counter Mode ([GCM](https://csrc.nist.gov/publications/detail/sp/800-38d/final)) - Counter with Cipher Block Chaining-Message Authentication Code ([CCM](https://csrc.nist.gov/publications/detail/sp/800-38c/final)) - OCB Authenticated-Encryption Algorithm ([OCB](https://tools.ietf.org/html/rfc7253)) #### Password-Based Key Derivation Function - [PBKDF1](https://tools.ietf.org/html/rfc2898#section-5.1) (Password-Based Key Derivation Function 1) - [PBKDF2](https://tools.ietf.org/html/rfc2898#section-5.2) (Password-Based Key Derivation Function 2) - [HKDF](https://tools.ietf.org/html/rfc5869) (HMAC-based Extract-and-Expand Key Derivation Function) - [Scrypt](https://tools.ietf.org/html/rfc7914) (The scrypt Password-Based Key Derivation Function) #### Data padding - [PKCS#5](https://www.rfc-editor.org/rfc/rfc2898.html) - [EMSA-PKCS1-v1_5 (Encoding Method for Signature)](https://www.rfc-editor.org/rfc/rfc3447#section-9.2) - [EME-PCKS1-v1_5 (Encoding Method for Encryption)](https://www.rfc-editor.org/rfc/rfc3447) - [PKCS#7](https://tools.ietf.org/html/rfc5652#section-6.3) - [Zero padding](https://en.wikipedia.org/wiki/Padding_(cryptography)#Zero_padding) - [ISO78164](https://www.embedx.com/pdfs/ISO_STD_7816/info_isoiec7816-4%7Bed21.0%7Den.pdf) - [ISO10126](https://en.wikipedia.org/wiki/Padding_(cryptography)#ISO_10126) - No padding #### Authenticated Encryption with Associated Data (AEAD) - [AEAD\_CHACHA20\_POLY1305](https://tools.ietf.org/html/rfc7539#section-2.8) - [AEAD\_XCHACHA20\_POLY1305](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha#section-2) ## Why [Why?](https://github.com/krzyzanowskim/CryptoSwift/discussions/982) [Because I can](https://github.com/krzyzanowskim/CryptoSwift/discussions/982#discussioncomment-3669415). ## How do I get involved? You want to help, great! Go ahead and fork our repo, make your changes and send us a pull request. ## Contribution Check out [CONTRIBUTING.md](CONTRIBUTING.md) for more information on how to help with CryptoSwift. - If you found a bug, [open a discussion](https://github.com/krzyzanowskim/CryptoSwift/discussions). - If you have a feature request, [open a discussion](https://github.com/krzyzanowskim/CryptoSwift/discussions). ## Installation ### Hardened Runtime (macOS) and Xcode Binary CryptoSwift.xcframework (Used by Swift Package Manager package integration) won't load properly in your app if the app uses **Sign to Run Locally** Signing Certificate with Hardened Runtime enabled. It is possible to setup Xcode like this. To solve the problem you have two options: - Use proper Signing Certificate, eg. *Development* <- this is the proper action - Use `Disable Library Validation` aka `com.apple.security.cs.disable-library-validation` entitlement #### Xcode Project To install CryptoSwift, add it as a submodule to your project (on the top level project directory): git submodule add https://github.com/krzyzanowskim/CryptoSwift.git It is recommended to enable [Whole-Module Optimization](https://swift.org/blog/whole-module-optimizations/) to gain better performance. Non-optimized build results in significantly worse performance. #### Swift Package Manager You can use [Swift Package Manager](https://swift.org/package-manager/) and specify dependency in `Package.swift` by adding this: ```swift .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "1.9.0") ``` See: [Package.swift - manual](https://blog.krzyzanowskim.com/2016/08/09/package-swift-manual/) Notice: Swift Package Manager uses debug configuration for debug Xcode build, that may result in significant (up to x10000) worse performance. Performance characteristic is different in Release build. To overcome this problem, consider embed `CryptoSwift.xcframework` described below. #### Carthage You can use [Carthage](https://github.com/Carthage/Carthage). Specify in Cartfile: ```ruby github "krzyzanowskim/CryptoSwift" ``` Run `carthage` to build the framework and drag the built CryptoSwift.framework into your Xcode project. Follow [build instructions](https://github.com/Carthage/Carthage#getting-started). [Common issues](https://github.com/krzyzanowskim/CryptoSwift/discussions/983#discussioncomment-3669433). #### CocoaPods > **Note**: CocoaPods is deprecated and no longer recommended for new projects. Use Swift Package Manager or Carthage instead. You can use [CocoaPods](https://cocoapods.org/pods/CryptoSwift). ```ruby pod 'CryptoSwift', '~> 1.8.4' ``` Bear in mind that CocoaPods will build CryptoSwift without [Whole-Module Optimization](https://swift.org/blog/whole-module-optimizations/) that may impact performance. You can change it manually after installation, or use [cocoapods-wholemodule](https://github.com/jedlewison/cocoapods-wholemodule) plugin. #### XCFramework XCFrameworks require Xcode 11 or later and they can be integrated similarly to how we’re used to integrating the `.framework` format. Please use script [scripts/build-framework.sh](scripts/build-framework.sh) to generate binary `CryptoSwift.xcframework` archive that you can use as a dependency in Xcode. CryptoSwift.xcframework is a Release (Optimized) binary that offer best available Swift code performance. Screen Shot 2020-10-27 at 00 06 32 #### Embedded Framework Embedded frameworks require a minimum deployment target of iOS 11.0 or macOS Sierra (10.13). Drag the `CryptoSwift.xcodeproj` file into your Xcode project, and add appropriate framework as a dependency to your target. Now select your App and choose the General tab for the app target. Find *Embedded Binaries* and press "+", then select `CryptoSwift.framework` (iOS, macOS, watchOS or tvOS) ![](https://cloud.githubusercontent.com/assets/758033/10834511/25a26852-7e9a-11e5-8c01-6cc8f1838459.png) Sometimes "embedded framework" option is not available. In that case, you have to add new build phase for the target. ![](https://cloud.githubusercontent.com/assets/758033/18415615/d5edabb0-77f8-11e6-8c94-f41d9fc2b8cb.png) ##### iOS, macOS, watchOS, tvOS In the project, you'll find [single scheme](https://mxcl.dev/PromiseKit/news/2016/08/Multiplatform-Single-Scheme-Xcode-Projects/) for all platforms: - CryptoSwift #### Swift versions support - Swift 1.2: branch [swift12](https://github.com/krzyzanowskim/CryptoSwift/tree/swift12) version <= 0.0.13 - Swift 2.1: branch [swift21](https://github.com/krzyzanowskim/CryptoSwift/tree/swift21) version <= 0.2.3 - Swift 2.2, 2.3: branch [swift2](https://github.com/krzyzanowskim/CryptoSwift/tree/swift2) version <= 0.5.2 - Swift 3.1, branch [swift3](https://github.com/krzyzanowskim/CryptoSwift/tree/swift3) version <= 0.6.9 - Swift 3.2, branch [swift32](https://github.com/krzyzanowskim/CryptoSwift/tree/swift32) version = 0.7.0 - Swift 4.0, branch [swift4](https://github.com/krzyzanowskim/CryptoSwift/tree/swift4) version <= 0.12.0 - Swift 4.2, branch [swift42](https://github.com/krzyzanowskim/CryptoSwift/tree/swift42) version <= 0.15.0 - Swift 5.0, branch [swift5](https://github.com/krzyzanowskim/CryptoSwift/tree/swift5) version <= 1.2.0 - Swift 5.1, branch [swift51](https://github.com/krzyzanowskim/CryptoSwift/tree/swift51) version <= 1.3.3 - Swift 5.3, branch [swift53](https://github.com/krzyzanowskim/CryptoSwift/tree/swift53) version <= 1.8.5 - Swift 6.2 and newer, branch [main](https://github.com/krzyzanowskim/CryptoSwift/tree/main) ## How-to * [Basics (data types, conversion, ...)](#basics) * [Digest (MD5, SHA...)](#calculate-digest) * [Message authenticators (HMAC, CMAC...)](#message-authenticators-1) * [Password-Based Key Derivation Function (PBKDF2, ...)](#password-based-key-derivation-functions) * [HMAC-based Key Derivation Function (HKDF)](#hmac-based-key-derivation-function) * [Data Padding](#data-padding) * [ChaCha20](#chacha20) * [Rabbit](#rabbit) * [Blowfish](#blowfish) * [AES - Advanced Encryption Standard](#aes) * [AES-GCM](#aes-gcm) * [Authenticated Encryption with Associated Data (AEAD)](#aead) ##### Basics ```swift import CryptoSwift ``` CryptoSwift uses array of bytes aka `Array` as a base type for all operations. Every data may be converted to a stream of bytes. You will find convenience functions that accept `String` or `Data`, and it will be internally converted to the array of bytes. ##### Data types conversion For your convenience, **CryptoSwift** provides two functions to easily convert an array of bytes to `Data` or `Data` to an array of bytes: Data from bytes: ```swift let data = Data([0x01, 0x02, 0x03]) ``` `Data` to `Array` ```swift let bytes = data.byteArray // [1,2,3] ``` [Hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) encoding: ```swift let bytes = Array(hex: "0x010203") // [1,2,3] let hex = bytes.toHexString() // "010203" ``` Build bytes out of `String` ```swift let bytes: Array = "cipherkey".bytes // Array("cipherkey".utf8) ``` Also... check out helpers that work with **Base64** encoded data: ```swift "aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64ToString(cipher) "aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64(cipher) bytes.toBase64() ``` ##### Calculate Digest Hashing a data or array of bytes (aka `Array`) ```swift /* Hash struct usage */ let bytes: Array = [0x01, 0x02, 0x03] let digest = input.md5() let digest = Digest.md5(bytes) ``` ```swift let data = Data([0x01, 0x02, 0x03]) let hash = data.md5() let hash = data.sha1() let hash = data.sha224() let hash = data.sha256() let hash = data.sha384() let hash = data.sha512() ``` ```swift do { var digest = MD5() let partial1 = try digest.update(withBytes: [0x31, 0x32]) let partial2 = try digest.update(withBytes: [0x33]) let result = try digest.finish() } catch { } ``` Hashing a String and printing result ```swift let hash = "123".md5() // "123".bytes.md5() ``` ##### Calculate CRC ```swift bytes.crc16() data.crc16() bytes.crc32() data.crc32() ``` ##### Message authenticators ```swift // Calculate Message Authentication Code (MAC) for message let key: Array = [1,2,3,4,5,6,7,8,9,10,...] try Poly1305(key: key).authenticate(bytes) try HMAC(key: key, variant: .sha256).authenticate(bytes) try CMAC(key: key).authenticate(bytes) ``` ##### Password-Based Key Derivation Functions ```swift let password: Array = Array("s33krit".utf8) let salt: Array = Array("nacllcan".utf8) let key = try PKCS5.PBKDF2(password: password, salt: salt, iterations: 4096, keyLength: 32, variant: .sha2(.sha256)).calculate() ``` ```swift let password: Array = Array("s33krit".utf8) let salt: Array = Array("nacllcan".utf8) // Scrypt implementation does not implement work parallelization, so `p` parameter will // increase the work time even in multicore systems let key = try Scrypt(password: password, salt: salt, dkLen: 64, N: 16384, r: 8, p: 1).calculate() ``` ##### HMAC-based Key Derivation Function ```swift let password: Array = Array("s33krit".utf8) let salt: Array = Array("nacllcan".utf8) let key = try HKDF(password: password, salt: salt, variant: .sha256).calculate() ``` ##### Data Padding Some content-encryption algorithms assume the input length is a multiple of `k` octets, where `k` is greater than one. For such algorithms, the input shall be padded. ```swift Padding.pkcs7.add(to: bytes, blockSize: AES.blockSize) ``` #### Working with Ciphers ##### ChaCha20 ```swift let encrypted = try ChaCha20(key: key, iv: iv).encrypt(message) let decrypted = try ChaCha20(key: key, iv: iv).decrypt(encrypted) ``` ##### Rabbit ```swift let encrypted = try Rabbit(key: key, iv: iv).encrypt(message) let decrypted = try Rabbit(key: key, iv: iv).decrypt(encrypted) ``` ##### Blowfish ```swift let encrypted = try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(message) let decrypted = try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(encrypted) ``` ##### AES Notice regarding padding: *Manual padding of data is optional, and CryptoSwift is using PKCS7 padding by default. If you need to manually disable/enable padding, you can do this by setting parameter for __AES__ class* Variant of AES encryption (AES-128, AES-192, AES-256) depends on given key length: - AES-128 = 16 bytes - AES-192 = 24 bytes - AES-256 = 32 bytes AES-256 example ```swift let encryptedBytes = try AES(key: [1,2,3,...,32], blockMode: CBC(iv: [1,2,3,...,16]), padding: .pkcs7) ``` Full example: ```swift let password: [UInt8] = Array("s33krit".utf8) let salt: [UInt8] = Array("nacllcan".utf8) /* Generate a key from a `password`. Optional if you already have a key */ let key = try PKCS5.PBKDF2( password: password, salt: salt, iterations: 4096, keyLength: 32, /* AES-256 */ variant: .sha256 ).calculate() /* Generate random IV value. IV is public value. Either need to generate, or get it from elsewhere */ let iv = AES.randomIV(AES.blockSize) /* AES cryptor instance */ let aes = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7) /* Encrypt Data */ let inputData = Data() let encryptedBytes = try aes.encrypt(inputData.byteArray) let encryptedData = Data(encryptedBytes) /* Decrypt Data */ let decryptedBytes = try aes.decrypt(encryptedData.byteArray) let decryptedData = Data(decryptedBytes) ``` ###### All at once ```swift do { let aes = try AES(key: "keykeykeykeykeyk", iv: "drowssapdrowssap") // aes128 let ciphertext = try aes.encrypt(Array("Nullam quis risus eget urna mollis ornare vel eu leo.".utf8)) } catch { } ``` ###### Incremental updates Incremental operations use instance of Cryptor and encrypt/decrypt one part at a time, this way you can save on memory for large files. ```swift do { var encryptor = try AES(key: "keykeykeykeykeyk", iv: "drowssapdrowssap").makeEncryptor() var ciphertext = Array() // aggregate partial results ciphertext += try encryptor.update(withBytes: Array("Nullam quis risus ".utf8)) ciphertext += try encryptor.update(withBytes: Array("eget urna mollis ".utf8)) ciphertext += try encryptor.update(withBytes: Array("ornare vel eu leo.".utf8)) // finish at the end ciphertext += try encryptor.finish() print(ciphertext.toHexString()) } catch { print(error) } ``` ###### AES Advanced usage ```swift let input: Array = [0,1,2,3,4,5,6,7,8,9] let key: Array = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00] let iv: Array = // Random bytes of `AES.blockSize` length do { let encrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(input) let decrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(encrypted) } catch { print(error) } ``` AES without data padding ```swift let input: Array = [0,1,2,3,4,5,6,7,8,9] let encrypted: Array = try! AES(key: Array("secret0key000000".utf8), blockMode: CBC(iv: Array("0123456789012345".utf8)), padding: .noPadding).encrypt(input) ``` Using convenience extensions ```swift let plain = Data([0x01, 0x02, 0x03]) let encrypted = try! plain.encrypt(ChaCha20(key: key, iv: iv)) let decrypted = try! encrypted.decrypt(ChaCha20(key: key, iv: iv)) ``` ##### AES-GCM The result of Galois/Counter Mode (GCM) encryption is ciphertext and **authentication tag**, that is later used to decryption. encryption ```swift do { // In combined mode, the authentication tag is directly appended to the encrypted message. This is usually what you want. let gcm = GCM(iv: iv, mode: .combined) let aes = try AES(key: key, blockMode: gcm, padding: .noPadding) let encrypted = try aes.encrypt(plaintext) let tag = gcm.authenticationTag } catch { // failed } ``` decryption ```swift do { // In combined mode, the authentication tag is appended to the encrypted message. This is usually what you want. let gcm = GCM(iv: iv, mode: .combined) let aes = try AES(key: key, blockMode: gcm, padding: .noPadding) return try aes.decrypt(encrypted) } catch { // failed } ``` **Note**: GCM instance is not intended to be reused. So you can't use the same `GCM` instance from encoding to also perform decoding. ##### AES-CCM The result of Counter with Cipher Block Chaining-Message Authentication Code encryption is ciphertext and **authentication tag**, that is later used to decryption. ```swift do { // The authentication tag is appended to the encrypted message. let tagLength = 8 let ccm = CCM(iv: iv, tagLength: tagLength, messageLength: ciphertext.count - tagLength, additionalAuthenticatedData: data) let aes = try AES(key: key, blockMode: ccm, padding: .noPadding) return try aes.decrypt(encrypted) } catch { // failed } ``` Check documentation or CCM specification for valid parameters for CCM. ##### AEAD ```swift let encrypt = try AEADChaCha20Poly1305.encrypt(plaintext, key: key, iv: nonce, authenticationHeader: header) let decrypt = try AEADChaCha20Poly1305.decrypt(ciphertext, key: key, iv: nonce, authenticationHeader: header, authenticationTag: tagArr: tag) ``` ##### RSA RSA initialization from parameters ```swift let input: Array = [0,1,2,3,4,5,6,7,8,9] let n: Array = // RSA modulus let e: Array = // RSA public exponent let d: Array = // RSA private exponent let rsa = RSA(n: n, e: e, d: d) do { let encrypted = try rsa.encrypt(input) let decrypted = try rsa.decrypt(encrypted) } catch { print(error) } ``` RSA key generation ```swift let rsa = try RSA(keySize: 2048) // This generates a modulus, public exponent and private exponent with the given size ``` RSA Encryption & Decryption Example ``` swift // Alice Generates a Private Key let alicesPrivateKey = try RSA(keySize: 1024) // Alice shares her **public** key with Bob let alicesPublicKeyData = try alicesPrivateKey.publicKeyExternalRepresentation() // Bob receives the raw external representation of Alices public key and imports it let bobsImportOfAlicesPublicKey = try RSA(rawRepresentation: alicesPublicKeyData) // Bob can now encrypt a message for Alice using her public key let message = "Hi Alice! This is Bob!" let privateMessage = try bobsImportOfAlicesPublicKey.encrypt(message.bytes) // This results in some encrypted output like this // URcRwG6LfH63zOQf2w+HIllPri9Rb6hFlXbi/bh03zPl2MIIiSTjbAPqbVFmoF3RmDzFjIarIS7ZpT57a1F+OFOJjx50WYlng7dioKFS/rsuGHYnMn4csjCRF6TAqvRQcRnBueeINRRA8SLaLHX6sZuQkjIE5AoHJwgavmiv8PY= // Bob can now send this encrypted message to Alice without worrying about people being able to read the original contents // Alice receives the encrypted message and uses her private key to decrypt the data and recover the original message let originalDecryptedMessage = try alicesPrivateKey.decrypt(privateMessage) print(String(data: Data(originalDecryptedMessage), encoding: .utf8)) // "Hi Alice! This is Bob!" ``` RSA Signature & Verification Example ``` swift // Alice Generates a Private Key let alicesPrivateKey = try RSA(keySize: 1024) // Alice wants to sign a message that she agrees with let messageAliceSupports = "Hi my name is Alice!" let alicesSignature = try alicesPrivateKey.sign(messageAliceSupports.bytes) // Alice shares her Public key and the signature with Bob let alicesPublicKeyData = try alicesPrivateKey.publicKeyExternalRepresentation() // Bob receives the raw external representation of Alices Public key and imports it! let bobsImportOfAlicesPublicKey = try RSA(rawRepresentation: alicesPublicKeyData) // Bob can now verify that Alice signed the message using the Private key associated with her shared Public key. let verifiedSignature = try bobsImportOfAlicesPublicKey.verify(signature: alicesSignature, for: "Hi my name is Alice!".bytes) if verifiedSignature == true { // Bob knows that the signature Alice provided is valid for the message and was signed using the Private key associated with Alices shared Public key. } else { // The signature was invalid, so either // - the message Alice signed was different then what we expected. // - or Alice used a Private key that isn't associated with the shared Public key that Bob has. } ``` CryptoSwift RSA Key -> Apple's Security Framework SecKey Example ``` swift /// Starting with a CryptoSwift RSA Key let rsaKey = try RSA(keySize: 1024) /// Define your Keys attributes let attributes: [String:Any] = [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, // or kSecAttrKeyClassPublic kSecAttrKeySizeInBits as String: 1024, // The appropriate bits kSecAttrIsPermanent as String: false ] var error:Unmanaged? = nil guard let rsaSecKey = try SecKeyCreateWithData(rsaKey.externalRepresentation() as CFData, attributes as CFDictionary, &error) else { /// Error constructing SecKey from raw key data return } /// You now have an RSA SecKey for use with Apple's Security framework ``` Apple's Security Framework SecKey -> CryptoSwift RSA Key Example ``` swift /// Starting with a SecKey RSA Key let rsaSecKey:SecKey /// Copy External Representation var externalRepError:Unmanaged? guard let cfdata = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) else { /// Failed to copy external representation for RSA SecKey return } /// Instantiate the RSA Key from the raw external representation let rsaKey = try RSA(rawRepresentation: cfdata as Data) /// You now have a CryptoSwift RSA Key ``` ## Author CryptoSwift is owned and maintained by [Marcin Krzyżanowski](https://www.krzyzanowskim.com) You can follow me on Twitter at [@krzyzanowskim](https://x.com/krzyzanowskim) for project updates and releases. # Cryptography Notice This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See https://www.wassenaar.org/ for more information. ## License Copyright (C) 2014-2025 Marcin Krzyżanowski This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, **an acknowledgment in the product documentation is required**. - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - This notice may not be removed or altered from any source or binary distribution. - Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the "Marcin Krzyzanowski" (https://krzyzanowskim.com/).' ## Changelog See [CHANGELOG](./CHANGELOG) file. ================================================ FILE: Sources/CryptoSwift/AEAD/AEAD.swift ================================================ // // AEAD.swift // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // // https://www.iana.org/assignments/aead-parameters/aead-parameters.xhtml /// Authenticated Encryption with Associated Data (AEAD) public protocol AEAD { static var kLen: Int { get } // key length static var ivRange: Range { get } // nonce length } extension AEAD { static func calculateAuthenticationTag(authenticator: Authenticator, cipherText: Array, authenticationHeader: Array) throws -> Array { let headerPadding = ((16 - (authenticationHeader.count & 0xf)) & 0xf) let cipherPadding = ((16 - (cipherText.count & 0xf)) & 0xf) var mac = authenticationHeader mac += Array(repeating: 0, count: headerPadding) mac += cipherText mac += Array(repeating: 0, count: cipherPadding) mac += UInt64(bigEndian: UInt64(authenticationHeader.count)).bytes() mac += UInt64(bigEndian: UInt64(cipherText.count)).bytes() return try authenticator.authenticate(mac) } } ================================================ FILE: Sources/CryptoSwift/AEAD/AEADChaCha20Poly1305.swift ================================================ // // AEADChaCha20Poly1305.swift // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // // https://tools.ietf.org/html/rfc7539#section-2.8.1 /// AEAD_CHACHA20_POLY1305 public final class AEADChaCha20Poly1305: AEAD { public static let kLen = 32 // key length public static var ivRange = Range(12...12) /// Authenticated encryption public static func encrypt(_ plainText: Array, key: Array, iv: Array, authenticationHeader: Array) throws -> (cipherText: Array, authenticationTag: Array) { let cipher = try ChaCha20(key: key, iv: iv) return try self.encrypt(cipher: cipher, plainText, key: key, iv: iv, authenticationHeader: authenticationHeader) } public static func encrypt(cipher: Cipher, _ plainText: Array, key: Array, iv: Array, authenticationHeader: Array) throws -> (cipherText: Array, authenticationTag: Array) { var polykey = Array(repeating: 0, count: kLen) var toEncrypt = polykey polykey = try cipher.encrypt(polykey) toEncrypt += polykey toEncrypt += plainText let fullCipherText = try cipher.encrypt(toEncrypt) let cipherText = Array(fullCipherText.dropFirst(64)) let tag = try calculateAuthenticationTag(authenticator: Poly1305(key: polykey), cipherText: cipherText, authenticationHeader: authenticationHeader) return (cipherText, tag) } /// Authenticated decryption public static func decrypt(_ cipherText: Array, key: Array, iv: Array, authenticationHeader: Array, authenticationTag: Array) throws -> (plainText: Array, success: Bool) { let cipher = try ChaCha20(key: key, iv: iv) return try self.decrypt(cipher: cipher, cipherText: cipherText, key: key, iv: iv, authenticationHeader: authenticationHeader, authenticationTag: authenticationTag) } static func decrypt(cipher: Cipher, cipherText: Array, key: Array, iv: Array, authenticationHeader: Array, authenticationTag: Array) throws -> (plainText: Array, success: Bool) { let polykey = try cipher.encrypt(Array(repeating: 0, count: self.kLen)) let mac = try calculateAuthenticationTag(authenticator: Poly1305(key: polykey), cipherText: cipherText, authenticationHeader: authenticationHeader) guard mac == authenticationTag else { return (cipherText, false) } var toDecrypt = Array(reserveCapacity: cipherText.count + 64) toDecrypt += polykey toDecrypt += polykey toDecrypt += cipherText let fullPlainText = try cipher.decrypt(toDecrypt) let plainText = Array(fullPlainText.dropFirst(64)) return (plainText, true) } } ================================================ FILE: Sources/CryptoSwift/AEAD/AEADXChaCha20Poly1305.swift ================================================ // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation /// This class implements the XChaCha20-Poly1305 Authenticated Encryption with /// Associated Data (AEAD_XCHACHA20_POLY1305) construction, providing both encryption and authentication. /// /// For more information about the XChaCha20-Poly1305 algorithm, refer to the IETF draft: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha public final class AEADXChaCha20Poly1305: AEAD { /// The key length (in bytes) required for the XChaCha20 cipher (32 bytes). public static let kLen = 32 // key length /// The valid range of initialization vector lengths for the XChaCha20 cipher (12 bytes). public static var ivRange = Range(12...12) /// Encrypts the given plaintext using the XChaCha20 cipher and generates an authentication /// tag using the Poly1305 MAC. /// /// - Parameters: /// - plainText: The plaintext to be encrypted. /// - key: The encryption key. /// - iv: The initialization vector. /// - authenticationHeader: The authentication header. /// - Returns: A tuple containing the ciphertext and authentication tag. /// - Throws: An error if encryption fails. public static func encrypt( _ plainText: Array, key: Array, iv: Array, authenticationHeader: Array ) throws -> (cipherText: Array, authenticationTag: Array) { try AEADChaCha20Poly1305.encrypt( cipher: XChaCha20(key: key, iv: iv), plainText, key: key, iv: iv, authenticationHeader: authenticationHeader ) } /// Decrypts the given ciphertext using the XChaCha20 cipher and verifies the authentication /// tag using the Poly1305 MAC. /// /// - Parameters: /// - cipherText: The ciphertext to be decrypted. /// - key: The decryption key. /// - iv: The initialization vector. /// - authenticationHeader: The authentication header. /// - authenticationTag: The authentication tag. /// - Returns: A tuple containing the decrypted plaintext and a boolean value indicating /// the success of the decryption and authentication process. /// - Throws: An error if decryption fails. public static func decrypt( _ cipherText: Array, key: Array, iv: Array, authenticationHeader: Array, authenticationTag: Array ) throws -> (plainText: Array, success: Bool) { try AEADChaCha20Poly1305.decrypt( cipher: XChaCha20(key: key, iv: iv), cipherText: cipherText, key: key, iv: iv, authenticationHeader: authenticationHeader, authenticationTag: authenticationTag ) } } ================================================ FILE: Sources/CryptoSwift/AES.Cryptors.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // MARK: Cryptors extension AES: Cryptors { @inlinable public func makeEncryptor() throws -> Cryptor & Updatable { let blockSize = blockMode.customBlockSize ?? AES.blockSize let worker = try blockMode.worker(blockSize: blockSize, cipherOperation: encrypt, encryptionOperation: encrypt) if worker is StreamModeWorker { return try StreamEncryptor(blockSize: blockSize, padding: padding, worker) } return try BlockEncryptor(blockSize: blockSize, padding: padding, worker) } @inlinable public func makeDecryptor() throws -> Cryptor & Updatable { let blockSize = blockMode.customBlockSize ?? AES.blockSize let cipherOperation: CipherOperationOnBlock = blockMode.options.contains(.useEncryptToDecrypt) == true ? encrypt : decrypt let worker = try blockMode.worker(blockSize: blockSize, cipherOperation: cipherOperation, encryptionOperation: encrypt) if worker is StreamModeWorker { return try StreamDecryptor(blockSize: blockSize, padding: padding, worker) } return try BlockDecryptor(blockSize: blockSize, padding: padding, worker) } } ================================================ FILE: Sources/CryptoSwift/AES.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // Implementation of Gladman algorithm http://www.gladman.me.uk/AES // /// The Advanced Encryption Standard (AES) public final class AES: BlockCipher { public enum Error: Swift.Error { /// Invalid key case invalidKeySize /// Data padding is required case dataPaddingRequired /// Invalid Data case invalidData } public enum Variant: Int { case aes128 = 1, aes192, aes256 var Nk: Int { // Nk words [4, 6, 8][self.rawValue - 1] } var Nb: Int { // Nb words 4 } var Nr: Int { // Nr self.Nk + 6 } } @usableFromInline internal let variantNr: Int @usableFromInline internal let variantNb: Int @usableFromInline internal let variantNk: Int public static let blockSize: Int = 16 // 128 /8 public let keySize: Int /// AES Variant public let variant: Variant // Parameters let key: Key @usableFromInline let blockMode: BlockMode @usableFromInline let padding: Padding // @usableFromInline internal lazy var expandedKey: Array> = self.expandKey(self.key, variant: self.variant) @usableFromInline internal lazy var expandedKeyInv: Array> = self.expandKeyInv(self.key, variant: self.variant) private lazy var sBoxes: (sBox: Array, invSBox: Array) = self.calculateSBox() private lazy var sBox: Array = self.sBoxes.sBox private lazy var sBoxInv: Array = self.sBoxes.invSBox // Parameters for Linear Congruence Generators private static let Rcon: Array = [ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d ] @usableFromInline static let T0: Array = [0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0xdf2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x3010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0xbf0f0fb, 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x2f7f7f5, 0x4fcccc83, 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x8f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, 0xc040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0xf05050a, 0xb59a9a2f, 0x907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, 0xf55353a6, 0x68d1d1b9, 0x0, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, 0x10f9f9e9, 0x6020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x4f5f5f1, 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0xef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0xa06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 0xfa5656ac, 0x7f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x5030306, 0x1f6f6f7, 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c] @usableFromInline static let T0_INV: Array = [0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 0x2752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566, 0x728ebb2, 0x3c2b52f, 0x9a7bc586, 0xa50837d3, 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x69f715e, 0x51106ebd, 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 0x55dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x0, 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0xfe75793, 0xd296eeb4, 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, 0xaba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0xb0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0xd927850, 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x97826cd, 0xf418596e, 0x1b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 0x8cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, 0xf7daec41, 0xe50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546, 0x4ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 0xc25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0] @usableFromInline static let T1: Array = [0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x1010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x5050a0f, 0x9a9a2fb5, 0x7070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, 0x5353a6f5, 0xd1d1b968, 0x0, 0xededc12c, 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf, 0xf9f9e910, 0x2020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0xc0c1814, 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, 0xdedea779, 0x5e5ebce2, 0xb0b161d, 0xdbdbad76, 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0xa0a141e, 0x494992db, 0x6060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x8081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x3030605, 0xf6f6f701, 0xe0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, 0x8c8c038f, 0xa1a159f8, 0x89890980, 0xd0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, 0x2d2d5a77, 0xf0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a] @usableFromInline static let T1_INV: Array = [0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, 0x459d1ff1, 0x58faacab, 0x3e34b93, 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 0xa362b58f, 0x5ab1de49, 0x1bba2567, 0xeea4598, 0xc0fe5de1, 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, 0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b, 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19, 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x24b72e2, 0x8f1fe357, 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x837d3a5, 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b, 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5, 0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, 0x8a213ef9, 0x6dd963d, 0x53eddae, 0xbde64d46, 0x8d5491b5, 0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697, 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db, 0xa7ca147, 0xf427ce9, 0x1e84f8c9, 0x0, 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb, 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2, 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0xd090e0b, 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x775af4c, 0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3, 0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0xbd49836, 0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09, 0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x99fead4, 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d, 0x4daacc54, 0x496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c, 0xca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, 0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879, 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x1a83971, 0xb30c08de, 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042] @usableFromInline static let T2: Array = [0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x1020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x4080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x50a0f05, 0x9a2fb59a, 0x70e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x9121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, 0x53a6f553, 0xd1b968d1, 0x0, 0xedc12ced, 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45, 0xf9e910f9, 0x2040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0xc18140c, 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, 0xdea779de, 0x5ebce25e, 0xb161d0b, 0xdbad76db, 0xe0db3be0, 0x32645632, 0x3a744e3a, 0xa141e0a, 0x4992db49, 0x60c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x8101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x3060503, 0xf6f701f6, 0xe1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, 0x8c038f8c, 0xa159f8a1, 0x89098089, 0xd1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, 0x2d5a772d, 0xf1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16] @usableFromInline static let T2_INV: Array = [0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, 0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, 0xcc889176, 0x2f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, 0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e, 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x8f9942b, 0x48705868, 0x458f19fd, 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, 0x2830f287, 0xbf23b2a5, 0x302ba6a, 0x16ed5c82, 0xcf8a2b1c, 0x79a792b4, 0x7f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x506d5be, 0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, 0xc471055d, 0x6046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9, 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x0, 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0xefdfbff, 0x850f5638, 0xae3d1ed5, 0x2d362739, 0xf0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e, 0xa0cb167, 0x57930fe7, 0xeeb4d296, 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x90e0b0d, 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60, 0x1f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330, 0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978, 0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409, 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x4f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0, 0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0xbfb2e41, 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, 0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce, 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0xdff4195, 0xa8397101, 0xc08deb3, 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257] @usableFromInline static let T3: Array = [0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x2030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x80c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0xa0f0505, 0x2fb59a9a, 0xe090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, 0xa6f55353, 0xb968d1d1, 0x0, 0xc12ceded, 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545, 0xe910f9f9, 0x4060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x58a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, 0x3bab9090, 0xb838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 0xc0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 0x18c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, 0x61dcbdbd, 0xd868b8b, 0xf858a8a, 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x6050303, 0xf701f6f6, 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 0x7898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, 0x38f8c8c, 0x59f8a1a1, 0x9808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616] @usableFromInline static let T3_INV: Array = [0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, 0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x3e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, 0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58, 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45, 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, 0x30f28728, 0x23b2a5bf, 0x2ba6a03, 0xed5c8216, 0x8a2b1ccf, 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x6d5be05, 0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x532e18a, 0xa475ebf6, 0xb39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, 0x71055dc4, 0x46fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd, 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x7888b89, 0xe7385b19, 0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x0, 0x9838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e, 0xf563885, 0x3d1ed5ae, 0x3627392d, 0xa64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36, 0xcb1670a, 0x930fe757, 0xb4d296ee, 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0xe0b0d09, 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2, 0xdec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826, 0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f, 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef, 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 0x467f5165, 0x9d04ea5e, 0x15d358c, 0xfa737487, 0xfb2e410b, 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, 0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, 0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x8deb30c, 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8] @usableFromInline static let U1: Array = [0x0, 0xb0d090e, 0x161a121c, 0x1d171b12, 0x2c342438, 0x27392d36, 0x3a2e3624, 0x31233f2a, 0x58684870, 0x5365417e, 0x4e725a6c, 0x457f5362, 0x745c6c48, 0x7f516546, 0x62467e54, 0x694b775a, 0xb0d090e0, 0xbbdd99ee, 0xa6ca82fc, 0xadc78bf2, 0x9ce4b4d8, 0x97e9bdd6, 0x8afea6c4, 0x81f3afca, 0xe8b8d890, 0xe3b5d19e, 0xfea2ca8c, 0xf5afc382, 0xc48cfca8, 0xcf81f5a6, 0xd296eeb4, 0xd99be7ba, 0x7bbb3bdb, 0x70b632d5, 0x6da129c7, 0x66ac20c9, 0x578f1fe3, 0x5c8216ed, 0x41950dff, 0x4a9804f1, 0x23d373ab, 0x28de7aa5, 0x35c961b7, 0x3ec468b9, 0xfe75793, 0x4ea5e9d, 0x19fd458f, 0x12f04c81, 0xcb6bab3b, 0xc066a235, 0xdd71b927, 0xd67cb029, 0xe75f8f03, 0xec52860d, 0xf1459d1f, 0xfa489411, 0x9303e34b, 0x980eea45, 0x8519f157, 0x8e14f859, 0xbf37c773, 0xb43ace7d, 0xa92dd56f, 0xa220dc61, 0xf66d76ad, 0xfd607fa3, 0xe07764b1, 0xeb7a6dbf, 0xda595295, 0xd1545b9b, 0xcc434089, 0xc74e4987, 0xae053edd, 0xa50837d3, 0xb81f2cc1, 0xb31225cf, 0x82311ae5, 0x893c13eb, 0x942b08f9, 0x9f2601f7, 0x46bde64d, 0x4db0ef43, 0x50a7f451, 0x5baafd5f, 0x6a89c275, 0x6184cb7b, 0x7c93d069, 0x779ed967, 0x1ed5ae3d, 0x15d8a733, 0x8cfbc21, 0x3c2b52f, 0x32e18a05, 0x39ec830b, 0x24fb9819, 0x2ff69117, 0x8dd64d76, 0x86db4478, 0x9bcc5f6a, 0x90c15664, 0xa1e2694e, 0xaaef6040, 0xb7f87b52, 0xbcf5725c, 0xd5be0506, 0xdeb30c08, 0xc3a4171a, 0xc8a91e14, 0xf98a213e, 0xf2872830, 0xef903322, 0xe49d3a2c, 0x3d06dd96, 0x360bd498, 0x2b1ccf8a, 0x2011c684, 0x1132f9ae, 0x1a3ff0a0, 0x728ebb2, 0xc25e2bc, 0x656e95e6, 0x6e639ce8, 0x737487fa, 0x78798ef4, 0x495ab1de, 0x4257b8d0, 0x5f40a3c2, 0x544daacc, 0xf7daec41, 0xfcd7e54f, 0xe1c0fe5d, 0xeacdf753, 0xdbeec879, 0xd0e3c177, 0xcdf4da65, 0xc6f9d36b, 0xafb2a431, 0xa4bfad3f, 0xb9a8b62d, 0xb2a5bf23, 0x83868009, 0x888b8907, 0x959c9215, 0x9e919b1b, 0x470a7ca1, 0x4c0775af, 0x51106ebd, 0x5a1d67b3, 0x6b3e5899, 0x60335197, 0x7d244a85, 0x7629438b, 0x1f6234d1, 0x146f3ddf, 0x97826cd, 0x2752fc3, 0x335610e9, 0x385b19e7, 0x254c02f5, 0x2e410bfb, 0x8c61d79a, 0x876cde94, 0x9a7bc586, 0x9176cc88, 0xa055f3a2, 0xab58faac, 0xb64fe1be, 0xbd42e8b0, 0xd4099fea, 0xdf0496e4, 0xc2138df6, 0xc91e84f8, 0xf83dbbd2, 0xf330b2dc, 0xee27a9ce, 0xe52aa0c0, 0x3cb1477a, 0x37bc4e74, 0x2aab5566, 0x21a65c68, 0x10856342, 0x1b886a4c, 0x69f715e, 0xd927850, 0x64d90f0a, 0x6fd40604, 0x72c31d16, 0x79ce1418, 0x48ed2b32, 0x43e0223c, 0x5ef7392e, 0x55fa3020, 0x1b79aec, 0xaba93e2, 0x17ad88f0, 0x1ca081fe, 0x2d83bed4, 0x268eb7da, 0x3b99acc8, 0x3094a5c6, 0x59dfd29c, 0x52d2db92, 0x4fc5c080, 0x44c8c98e, 0x75ebf6a4, 0x7ee6ffaa, 0x63f1e4b8, 0x68fcedb6, 0xb1670a0c, 0xba6a0302, 0xa77d1810, 0xac70111e, 0x9d532e34, 0x965e273a, 0x8b493c28, 0x80443526, 0xe90f427c, 0xe2024b72, 0xff155060, 0xf418596e, 0xc53b6644, 0xce366f4a, 0xd3217458, 0xd82c7d56, 0x7a0ca137, 0x7101a839, 0x6c16b32b, 0x671bba25, 0x5638850f, 0x5d358c01, 0x40229713, 0x4b2f9e1d, 0x2264e947, 0x2969e049, 0x347efb5b, 0x3f73f255, 0xe50cd7f, 0x55dc471, 0x184adf63, 0x1347d66d, 0xcadc31d7, 0xc1d138d9, 0xdcc623cb, 0xd7cb2ac5, 0xe6e815ef, 0xede51ce1, 0xf0f207f3, 0xfbff0efd, 0x92b479a7, 0x99b970a9, 0x84ae6bbb, 0x8fa362b5, 0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d] @usableFromInline static let U2: Array = [0x0, 0xd090e0b, 0x1a121c16, 0x171b121d, 0x3424382c, 0x392d3627, 0x2e36243a, 0x233f2a31, 0x68487058, 0x65417e53, 0x725a6c4e, 0x7f536245, 0x5c6c4874, 0x5165467f, 0x467e5462, 0x4b775a69, 0xd090e0b0, 0xdd99eebb, 0xca82fca6, 0xc78bf2ad, 0xe4b4d89c, 0xe9bdd697, 0xfea6c48a, 0xf3afca81, 0xb8d890e8, 0xb5d19ee3, 0xa2ca8cfe, 0xafc382f5, 0x8cfca8c4, 0x81f5a6cf, 0x96eeb4d2, 0x9be7bad9, 0xbb3bdb7b, 0xb632d570, 0xa129c76d, 0xac20c966, 0x8f1fe357, 0x8216ed5c, 0x950dff41, 0x9804f14a, 0xd373ab23, 0xde7aa528, 0xc961b735, 0xc468b93e, 0xe757930f, 0xea5e9d04, 0xfd458f19, 0xf04c8112, 0x6bab3bcb, 0x66a235c0, 0x71b927dd, 0x7cb029d6, 0x5f8f03e7, 0x52860dec, 0x459d1ff1, 0x489411fa, 0x3e34b93, 0xeea4598, 0x19f15785, 0x14f8598e, 0x37c773bf, 0x3ace7db4, 0x2dd56fa9, 0x20dc61a2, 0x6d76adf6, 0x607fa3fd, 0x7764b1e0, 0x7a6dbfeb, 0x595295da, 0x545b9bd1, 0x434089cc, 0x4e4987c7, 0x53eddae, 0x837d3a5, 0x1f2cc1b8, 0x1225cfb3, 0x311ae582, 0x3c13eb89, 0x2b08f994, 0x2601f79f, 0xbde64d46, 0xb0ef434d, 0xa7f45150, 0xaafd5f5b, 0x89c2756a, 0x84cb7b61, 0x93d0697c, 0x9ed96777, 0xd5ae3d1e, 0xd8a73315, 0xcfbc2108, 0xc2b52f03, 0xe18a0532, 0xec830b39, 0xfb981924, 0xf691172f, 0xd64d768d, 0xdb447886, 0xcc5f6a9b, 0xc1566490, 0xe2694ea1, 0xef6040aa, 0xf87b52b7, 0xf5725cbc, 0xbe0506d5, 0xb30c08de, 0xa4171ac3, 0xa91e14c8, 0x8a213ef9, 0x872830f2, 0x903322ef, 0x9d3a2ce4, 0x6dd963d, 0xbd49836, 0x1ccf8a2b, 0x11c68420, 0x32f9ae11, 0x3ff0a01a, 0x28ebb207, 0x25e2bc0c, 0x6e95e665, 0x639ce86e, 0x7487fa73, 0x798ef478, 0x5ab1de49, 0x57b8d042, 0x40a3c25f, 0x4daacc54, 0xdaec41f7, 0xd7e54ffc, 0xc0fe5de1, 0xcdf753ea, 0xeec879db, 0xe3c177d0, 0xf4da65cd, 0xf9d36bc6, 0xb2a431af, 0xbfad3fa4, 0xa8b62db9, 0xa5bf23b2, 0x86800983, 0x8b890788, 0x9c921595, 0x919b1b9e, 0xa7ca147, 0x775af4c, 0x106ebd51, 0x1d67b35a, 0x3e58996b, 0x33519760, 0x244a857d, 0x29438b76, 0x6234d11f, 0x6f3ddf14, 0x7826cd09, 0x752fc302, 0x5610e933, 0x5b19e738, 0x4c02f525, 0x410bfb2e, 0x61d79a8c, 0x6cde9487, 0x7bc5869a, 0x76cc8891, 0x55f3a2a0, 0x58faacab, 0x4fe1beb6, 0x42e8b0bd, 0x99fead4, 0x496e4df, 0x138df6c2, 0x1e84f8c9, 0x3dbbd2f8, 0x30b2dcf3, 0x27a9ceee, 0x2aa0c0e5, 0xb1477a3c, 0xbc4e7437, 0xab55662a, 0xa65c6821, 0x85634210, 0x886a4c1b, 0x9f715e06, 0x9278500d, 0xd90f0a64, 0xd406046f, 0xc31d1672, 0xce141879, 0xed2b3248, 0xe0223c43, 0xf7392e5e, 0xfa302055, 0xb79aec01, 0xba93e20a, 0xad88f017, 0xa081fe1c, 0x83bed42d, 0x8eb7da26, 0x99acc83b, 0x94a5c630, 0xdfd29c59, 0xd2db9252, 0xc5c0804f, 0xc8c98e44, 0xebf6a475, 0xe6ffaa7e, 0xf1e4b863, 0xfcedb668, 0x670a0cb1, 0x6a0302ba, 0x7d1810a7, 0x70111eac, 0x532e349d, 0x5e273a96, 0x493c288b, 0x44352680, 0xf427ce9, 0x24b72e2, 0x155060ff, 0x18596ef4, 0x3b6644c5, 0x366f4ace, 0x217458d3, 0x2c7d56d8, 0xca1377a, 0x1a83971, 0x16b32b6c, 0x1bba2567, 0x38850f56, 0x358c015d, 0x22971340, 0x2f9e1d4b, 0x64e94722, 0x69e04929, 0x7efb5b34, 0x73f2553f, 0x50cd7f0e, 0x5dc47105, 0x4adf6318, 0x47d66d13, 0xdc31d7ca, 0xd138d9c1, 0xc623cbdc, 0xcb2ac5d7, 0xe815efe6, 0xe51ce1ed, 0xf207f3f0, 0xff0efdfb, 0xb479a792, 0xb970a999, 0xae6bbb84, 0xa362b58f, 0x805d9fbe, 0x8d5491b5, 0x9a4f83a8, 0x97468da3] @usableFromInline static let U3: Array = [0x0, 0x90e0b0d, 0x121c161a, 0x1b121d17, 0x24382c34, 0x2d362739, 0x36243a2e, 0x3f2a3123, 0x48705868, 0x417e5365, 0x5a6c4e72, 0x5362457f, 0x6c48745c, 0x65467f51, 0x7e546246, 0x775a694b, 0x90e0b0d0, 0x99eebbdd, 0x82fca6ca, 0x8bf2adc7, 0xb4d89ce4, 0xbdd697e9, 0xa6c48afe, 0xafca81f3, 0xd890e8b8, 0xd19ee3b5, 0xca8cfea2, 0xc382f5af, 0xfca8c48c, 0xf5a6cf81, 0xeeb4d296, 0xe7bad99b, 0x3bdb7bbb, 0x32d570b6, 0x29c76da1, 0x20c966ac, 0x1fe3578f, 0x16ed5c82, 0xdff4195, 0x4f14a98, 0x73ab23d3, 0x7aa528de, 0x61b735c9, 0x68b93ec4, 0x57930fe7, 0x5e9d04ea, 0x458f19fd, 0x4c8112f0, 0xab3bcb6b, 0xa235c066, 0xb927dd71, 0xb029d67c, 0x8f03e75f, 0x860dec52, 0x9d1ff145, 0x9411fa48, 0xe34b9303, 0xea45980e, 0xf1578519, 0xf8598e14, 0xc773bf37, 0xce7db43a, 0xd56fa92d, 0xdc61a220, 0x76adf66d, 0x7fa3fd60, 0x64b1e077, 0x6dbfeb7a, 0x5295da59, 0x5b9bd154, 0x4089cc43, 0x4987c74e, 0x3eddae05, 0x37d3a508, 0x2cc1b81f, 0x25cfb312, 0x1ae58231, 0x13eb893c, 0x8f9942b, 0x1f79f26, 0xe64d46bd, 0xef434db0, 0xf45150a7, 0xfd5f5baa, 0xc2756a89, 0xcb7b6184, 0xd0697c93, 0xd967779e, 0xae3d1ed5, 0xa73315d8, 0xbc2108cf, 0xb52f03c2, 0x8a0532e1, 0x830b39ec, 0x981924fb, 0x91172ff6, 0x4d768dd6, 0x447886db, 0x5f6a9bcc, 0x566490c1, 0x694ea1e2, 0x6040aaef, 0x7b52b7f8, 0x725cbcf5, 0x506d5be, 0xc08deb3, 0x171ac3a4, 0x1e14c8a9, 0x213ef98a, 0x2830f287, 0x3322ef90, 0x3a2ce49d, 0xdd963d06, 0xd498360b, 0xcf8a2b1c, 0xc6842011, 0xf9ae1132, 0xf0a01a3f, 0xebb20728, 0xe2bc0c25, 0x95e6656e, 0x9ce86e63, 0x87fa7374, 0x8ef47879, 0xb1de495a, 0xb8d04257, 0xa3c25f40, 0xaacc544d, 0xec41f7da, 0xe54ffcd7, 0xfe5de1c0, 0xf753eacd, 0xc879dbee, 0xc177d0e3, 0xda65cdf4, 0xd36bc6f9, 0xa431afb2, 0xad3fa4bf, 0xb62db9a8, 0xbf23b2a5, 0x80098386, 0x8907888b, 0x9215959c, 0x9b1b9e91, 0x7ca1470a, 0x75af4c07, 0x6ebd5110, 0x67b35a1d, 0x58996b3e, 0x51976033, 0x4a857d24, 0x438b7629, 0x34d11f62, 0x3ddf146f, 0x26cd0978, 0x2fc30275, 0x10e93356, 0x19e7385b, 0x2f5254c, 0xbfb2e41, 0xd79a8c61, 0xde94876c, 0xc5869a7b, 0xcc889176, 0xf3a2a055, 0xfaacab58, 0xe1beb64f, 0xe8b0bd42, 0x9fead409, 0x96e4df04, 0x8df6c213, 0x84f8c91e, 0xbbd2f83d, 0xb2dcf330, 0xa9ceee27, 0xa0c0e52a, 0x477a3cb1, 0x4e7437bc, 0x55662aab, 0x5c6821a6, 0x63421085, 0x6a4c1b88, 0x715e069f, 0x78500d92, 0xf0a64d9, 0x6046fd4, 0x1d1672c3, 0x141879ce, 0x2b3248ed, 0x223c43e0, 0x392e5ef7, 0x302055fa, 0x9aec01b7, 0x93e20aba, 0x88f017ad, 0x81fe1ca0, 0xbed42d83, 0xb7da268e, 0xacc83b99, 0xa5c63094, 0xd29c59df, 0xdb9252d2, 0xc0804fc5, 0xc98e44c8, 0xf6a475eb, 0xffaa7ee6, 0xe4b863f1, 0xedb668fc, 0xa0cb167, 0x302ba6a, 0x1810a77d, 0x111eac70, 0x2e349d53, 0x273a965e, 0x3c288b49, 0x35268044, 0x427ce90f, 0x4b72e202, 0x5060ff15, 0x596ef418, 0x6644c53b, 0x6f4ace36, 0x7458d321, 0x7d56d82c, 0xa1377a0c, 0xa8397101, 0xb32b6c16, 0xba25671b, 0x850f5638, 0x8c015d35, 0x97134022, 0x9e1d4b2f, 0xe9472264, 0xe0492969, 0xfb5b347e, 0xf2553f73, 0xcd7f0e50, 0xc471055d, 0xdf63184a, 0xd66d1347, 0x31d7cadc, 0x38d9c1d1, 0x23cbdcc6, 0x2ac5d7cb, 0x15efe6e8, 0x1ce1ede5, 0x7f3f0f2, 0xefdfbff, 0x79a792b4, 0x70a999b9, 0x6bbb84ae, 0x62b58fa3, 0x5d9fbe80, 0x5491b58d, 0x4f83a89a, 0x468da397] @usableFromInline static let U4: Array = [0x0, 0xe0b0d09, 0x1c161a12, 0x121d171b, 0x382c3424, 0x3627392d, 0x243a2e36, 0x2a31233f, 0x70586848, 0x7e536541, 0x6c4e725a, 0x62457f53, 0x48745c6c, 0x467f5165, 0x5462467e, 0x5a694b77, 0xe0b0d090, 0xeebbdd99, 0xfca6ca82, 0xf2adc78b, 0xd89ce4b4, 0xd697e9bd, 0xc48afea6, 0xca81f3af, 0x90e8b8d8, 0x9ee3b5d1, 0x8cfea2ca, 0x82f5afc3, 0xa8c48cfc, 0xa6cf81f5, 0xb4d296ee, 0xbad99be7, 0xdb7bbb3b, 0xd570b632, 0xc76da129, 0xc966ac20, 0xe3578f1f, 0xed5c8216, 0xff41950d, 0xf14a9804, 0xab23d373, 0xa528de7a, 0xb735c961, 0xb93ec468, 0x930fe757, 0x9d04ea5e, 0x8f19fd45, 0x8112f04c, 0x3bcb6bab, 0x35c066a2, 0x27dd71b9, 0x29d67cb0, 0x3e75f8f, 0xdec5286, 0x1ff1459d, 0x11fa4894, 0x4b9303e3, 0x45980eea, 0x578519f1, 0x598e14f8, 0x73bf37c7, 0x7db43ace, 0x6fa92dd5, 0x61a220dc, 0xadf66d76, 0xa3fd607f, 0xb1e07764, 0xbfeb7a6d, 0x95da5952, 0x9bd1545b, 0x89cc4340, 0x87c74e49, 0xddae053e, 0xd3a50837, 0xc1b81f2c, 0xcfb31225, 0xe582311a, 0xeb893c13, 0xf9942b08, 0xf79f2601, 0x4d46bde6, 0x434db0ef, 0x5150a7f4, 0x5f5baafd, 0x756a89c2, 0x7b6184cb, 0x697c93d0, 0x67779ed9, 0x3d1ed5ae, 0x3315d8a7, 0x2108cfbc, 0x2f03c2b5, 0x532e18a, 0xb39ec83, 0x1924fb98, 0x172ff691, 0x768dd64d, 0x7886db44, 0x6a9bcc5f, 0x6490c156, 0x4ea1e269, 0x40aaef60, 0x52b7f87b, 0x5cbcf572, 0x6d5be05, 0x8deb30c, 0x1ac3a417, 0x14c8a91e, 0x3ef98a21, 0x30f28728, 0x22ef9033, 0x2ce49d3a, 0x963d06dd, 0x98360bd4, 0x8a2b1ccf, 0x842011c6, 0xae1132f9, 0xa01a3ff0, 0xb20728eb, 0xbc0c25e2, 0xe6656e95, 0xe86e639c, 0xfa737487, 0xf478798e, 0xde495ab1, 0xd04257b8, 0xc25f40a3, 0xcc544daa, 0x41f7daec, 0x4ffcd7e5, 0x5de1c0fe, 0x53eacdf7, 0x79dbeec8, 0x77d0e3c1, 0x65cdf4da, 0x6bc6f9d3, 0x31afb2a4, 0x3fa4bfad, 0x2db9a8b6, 0x23b2a5bf, 0x9838680, 0x7888b89, 0x15959c92, 0x1b9e919b, 0xa1470a7c, 0xaf4c0775, 0xbd51106e, 0xb35a1d67, 0x996b3e58, 0x97603351, 0x857d244a, 0x8b762943, 0xd11f6234, 0xdf146f3d, 0xcd097826, 0xc302752f, 0xe9335610, 0xe7385b19, 0xf5254c02, 0xfb2e410b, 0x9a8c61d7, 0x94876cde, 0x869a7bc5, 0x889176cc, 0xa2a055f3, 0xacab58fa, 0xbeb64fe1, 0xb0bd42e8, 0xead4099f, 0xe4df0496, 0xf6c2138d, 0xf8c91e84, 0xd2f83dbb, 0xdcf330b2, 0xceee27a9, 0xc0e52aa0, 0x7a3cb147, 0x7437bc4e, 0x662aab55, 0x6821a65c, 0x42108563, 0x4c1b886a, 0x5e069f71, 0x500d9278, 0xa64d90f, 0x46fd406, 0x1672c31d, 0x1879ce14, 0x3248ed2b, 0x3c43e022, 0x2e5ef739, 0x2055fa30, 0xec01b79a, 0xe20aba93, 0xf017ad88, 0xfe1ca081, 0xd42d83be, 0xda268eb7, 0xc83b99ac, 0xc63094a5, 0x9c59dfd2, 0x9252d2db, 0x804fc5c0, 0x8e44c8c9, 0xa475ebf6, 0xaa7ee6ff, 0xb863f1e4, 0xb668fced, 0xcb1670a, 0x2ba6a03, 0x10a77d18, 0x1eac7011, 0x349d532e, 0x3a965e27, 0x288b493c, 0x26804435, 0x7ce90f42, 0x72e2024b, 0x60ff1550, 0x6ef41859, 0x44c53b66, 0x4ace366f, 0x58d32174, 0x56d82c7d, 0x377a0ca1, 0x397101a8, 0x2b6c16b3, 0x25671bba, 0xf563885, 0x15d358c, 0x13402297, 0x1d4b2f9e, 0x472264e9, 0x492969e0, 0x5b347efb, 0x553f73f2, 0x7f0e50cd, 0x71055dc4, 0x63184adf, 0x6d1347d6, 0xd7cadc31, 0xd9c1d138, 0xcbdcc623, 0xc5d7cb2a, 0xefe6e815, 0xe1ede51c, 0xf3f0f207, 0xfdfbff0e, 0xa792b479, 0xa999b970, 0xbb84ae6b, 0xb58fa362, 0x9fbe805d, 0x91b58d54, 0x83a89a4f, 0x8da39746] /// Initialize AES with variant calculated out of key length: /// - 16 bytes (AES-128) /// - 24 bytes (AES-192) /// - 32 bytes (AES-256) /// /// - parameter key: Key. Length of the key decides on AES variant. /// - parameter iv: Initialization Vector (Optional for some blockMode values) /// - parameter blockMode: Cipher mode of operation /// - parameter padding: Padding method. .pkcs7, .noPadding, .zeroPadding, ... /// /// - throws: AES.Error /// /// - returns: Instance public init(key: Array, blockMode: BlockMode, padding: Padding = .pkcs7) throws { self.key = Key(bytes: key) self.blockMode = blockMode self.padding = padding self.keySize = self.key.count // Validate key size switch self.keySize * 8 { case 128: self.variant = .aes128 case 192: self.variant = .aes192 case 256: self.variant = .aes256 default: throw Error.invalidKeySize } self.variantNb = self.variant.Nb self.variantNk = self.variant.Nk self.variantNr = self.variant.Nr } @inlinable internal func encrypt(block: ArraySlice) -> Array? { if self.blockMode.options.contains(.paddingRequired) && block.count != AES.blockSize { return Array(block) } let rounds = self.variantNr let rk = self.expandedKey let b00 = UInt32(block[block.startIndex.advanced(by: 0)]) let b01 = UInt32(block[block.startIndex.advanced(by: 1)]) << 8 let b02 = UInt32(block[block.startIndex.advanced(by: 2)]) << 16 let b03 = UInt32(block[block.startIndex.advanced(by: 3)]) << 24 var b0 = b00 | b01 | b02 | b03 let b10 = UInt32(block[block.startIndex.advanced(by: 4)]) let b11 = UInt32(block[block.startIndex.advanced(by: 5)]) << 8 let b12 = UInt32(block[block.startIndex.advanced(by: 6)]) << 16 let b13 = UInt32(block[block.startIndex.advanced(by: 7)]) << 24 var b1 = b10 | b11 | b12 | b13 let b20 = UInt32(block[block.startIndex.advanced(by: 8)]) let b21 = UInt32(block[block.startIndex.advanced(by: 9)]) << 8 let b22 = UInt32(block[block.startIndex.advanced(by: 10)]) << 16 let b23 = UInt32(block[block.startIndex.advanced(by: 11)]) << 24 var b2 = b20 | b21 | b22 | b23 let b30 = UInt32(block[block.startIndex.advanced(by: 12)]) let b31 = UInt32(block[block.startIndex.advanced(by: 13)]) << 8 let b32 = UInt32(block[block.startIndex.advanced(by: 14)]) << 16 let b33 = UInt32(block[block.startIndex.advanced(by: 15)]) << 24 var b3 = b30 | b31 | b32 | b33 let tLength = 4 let t = UnsafeMutablePointer.allocate(capacity: tLength) t.initialize(repeating: 0, count: tLength) defer { t.deinitialize(count: tLength) t.deallocate() } for r in 0..> 8) & 0xff)] let lb02 = AES.T2[Int((t[2] >> 16) & 0xff)] let lb03 = AES.T3[Int(t[3] >> 24)] b0 = lb00 ^ lb01 ^ lb02 ^ lb03 let lb10 = AES.T0[Int(t[1] & 0xff)] let lb11 = AES.T1[Int((t[2] >> 8) & 0xff)] let lb12 = AES.T2[Int((t[3] >> 16) & 0xff)] let lb13 = AES.T3[Int(t[0] >> 24)] b1 = lb10 ^ lb11 ^ lb12 ^ lb13 let lb20 = AES.T0[Int(t[2] & 0xff)] let lb21 = AES.T1[Int((t[3] >> 8) & 0xff)] let lb22 = AES.T2[Int((t[0] >> 16) & 0xff)] let lb23 = AES.T3[Int(t[1] >> 24)] b2 = lb20 ^ lb21 ^ lb22 ^ lb23 let lb30 = AES.T0[Int(t[3] & 0xff)] let lb31 = AES.T1[Int((t[0] >> 8) & 0xff)] let lb32 = AES.T2[Int((t[1] >> 16) & 0xff)] let lb33 = AES.T3[Int(t[2] >> 24)] b3 = lb30 ^ lb31 ^ lb32 ^ lb33 } // last round let r = rounds - 1 t[0] = b0 ^ rk[r][0] t[1] = b1 ^ rk[r][1] t[2] = b2 ^ rk[r][2] t[3] = b3 ^ rk[r][3] // rounds b0 = F1(t[0], t[1], t[2], t[3]) ^ rk[rounds][0] b1 = F1(t[1], t[2], t[3], t[0]) ^ rk[rounds][1] b2 = F1(t[2], t[3], t[0], t[1]) ^ rk[rounds][2] b3 = F1(t[3], t[0], t[1], t[2]) ^ rk[rounds][3] let encrypted: Array = [ UInt8(b0 & 0xff), UInt8((b0 >> 8) & 0xff), UInt8((b0 >> 16) & 0xff), UInt8((b0 >> 24) & 0xff), UInt8(b1 & 0xff), UInt8((b1 >> 8) & 0xff), UInt8((b1 >> 16) & 0xff), UInt8((b1 >> 24) & 0xff), UInt8(b2 & 0xff), UInt8((b2 >> 8) & 0xff), UInt8((b2 >> 16) & 0xff), UInt8((b2 >> 24) & 0xff), UInt8(b3 & 0xff), UInt8((b3 >> 8) & 0xff), UInt8((b3 >> 16) & 0xff), UInt8((b3 >> 24) & 0xff) ] return encrypted } @usableFromInline internal func decrypt(block: ArraySlice) -> Array? { if self.blockMode.options.contains(.paddingRequired) && block.count != AES.blockSize { return Array(block) } let rounds = self.variantNr let rk = self.expandedKeyInv // Save milliseconds by not using `block.toUInt32Array()` let b00 = UInt32(block[block.startIndex.advanced(by: 0)]) let b01 = UInt32(block[block.startIndex.advanced(by: 1)]) << 8 let b02 = UInt32(block[block.startIndex.advanced(by: 2)]) << 16 let b03 = UInt32(block[block.startIndex.advanced(by: 3)]) << 24 var b0 = b00 | b01 | b02 | b03 let b10 = UInt32(block[block.startIndex.advanced(by: 4)]) let b11 = UInt32(block[block.startIndex.advanced(by: 5)]) << 8 let b12 = UInt32(block[block.startIndex.advanced(by: 6)]) << 16 let b13 = UInt32(block[block.startIndex.advanced(by: 7)]) << 24 var b1 = b10 | b11 | b12 | b13 let b20 = UInt32(block[block.startIndex.advanced(by: 8)]) let b21 = UInt32(block[block.startIndex.advanced(by: 9)]) << 8 let b22 = UInt32(block[block.startIndex.advanced(by: 10)]) << 16 let b23 = UInt32(block[block.startIndex.advanced(by: 11)]) << 24 var b2 = b20 | b21 | b22 | b23 let b30 = UInt32(block[block.startIndex.advanced(by: 12)]) let b31 = UInt32(block[block.startIndex.advanced(by: 13)]) << 8 let b32 = UInt32(block[block.startIndex.advanced(by: 14)]) << 16 let b33 = UInt32(block[block.startIndex.advanced(by: 15)]) << 24 var b3 = b30 | b31 | b32 | b33 let tLength = 4 let t = UnsafeMutablePointer.allocate(capacity: tLength) t.initialize(repeating: 0, count: tLength) defer { t.deinitialize(count: tLength) t.deallocate() } for r in (2...rounds).reversed() { t[0] = b0 ^ rk[r][0] t[1] = b1 ^ rk[r][1] t[2] = b2 ^ rk[r][2] t[3] = b3 ^ rk[r][3] let b00 = AES.T0_INV[Int(t[0] & 0xff)] let b01 = AES.T1_INV[Int((t[3] >> 8) & 0xff)] let b02 = AES.T2_INV[Int((t[2] >> 16) & 0xff)] let b03 = AES.T3_INV[Int(t[1] >> 24)] b0 = b00 ^ b01 ^ b02 ^ b03 let b10 = AES.T0_INV[Int(t[1] & 0xff)] let b11 = AES.T1_INV[Int((t[0] >> 8) & 0xff)] let b12 = AES.T2_INV[Int((t[3] >> 16) & 0xff)] let b13 = AES.T3_INV[Int(t[2] >> 24)] b1 = b10 ^ b11 ^ b12 ^ b13 let b20 = AES.T0_INV[Int(t[2] & 0xff)] let b21 = AES.T1_INV[Int((t[1] >> 8) & 0xff)] let b22 = AES.T2_INV[Int((t[0] >> 16) & 0xff)] let b23 = AES.T3_INV[Int(t[3] >> 24)] b2 = b20 ^ b21 ^ b22 ^ b23 let b30 = AES.T0_INV[Int(t[3] & 0xff)] let b31 = AES.T1_INV[Int((t[2] >> 8) & 0xff)] let b32 = AES.T2_INV[Int((t[1] >> 16) & 0xff)] let b33 = AES.T3_INV[Int(t[0] >> 24)] b3 = b30 ^ b31 ^ b32 ^ b33 } // last round t[0] = b0 ^ rk[1][0] t[1] = b1 ^ rk[1][1] t[2] = b2 ^ rk[1][2] t[3] = b3 ^ rk[1][3] // rounds let lb00 = self.sBoxInv[Int(B0(t[0]))] let lb01 = (sBoxInv[Int(B1(t[3]))] << 8) let lb02 = (sBoxInv[Int(B2(t[2]))] << 16) let lb03 = (sBoxInv[Int(B3(t[1]))] << 24) b0 = lb00 | lb01 | lb02 | lb03 ^ rk[0][0] let lb10 = self.sBoxInv[Int(B0(t[1]))] let lb11 = (sBoxInv[Int(B1(t[0]))] << 8) let lb12 = (sBoxInv[Int(B2(t[3]))] << 16) let lb13 = (sBoxInv[Int(B3(t[2]))] << 24) b1 = lb10 | lb11 | lb12 | lb13 ^ rk[0][1] let lb20 = self.sBoxInv[Int(B0(t[2]))] let lb21 = (sBoxInv[Int(B1(t[1]))] << 8) let lb22 = (sBoxInv[Int(B2(t[0]))] << 16) let lb23 = (sBoxInv[Int(B3(t[3]))] << 24) b2 = lb20 | lb21 | lb22 | lb23 ^ rk[0][2] let lb30 = self.sBoxInv[Int(B0(t[3]))] let lb31 = (sBoxInv[Int(B1(t[2]))] << 8) let lb32 = (sBoxInv[Int(B2(t[1]))] << 16) let lb33 = (sBoxInv[Int(B3(t[0]))] << 24) b3 = lb30 | lb31 | lb32 | lb33 ^ rk[0][3] let result: Array = [ UInt8(b0 & 0xff), UInt8((b0 >> 8) & 0xff), UInt8((b0 >> 16) & 0xff), UInt8((b0 >> 24) & 0xff), UInt8(b1 & 0xff), UInt8((b1 >> 8) & 0xff), UInt8((b1 >> 16) & 0xff), UInt8((b1 >> 24) & 0xff), UInt8(b2 & 0xff), UInt8((b2 >> 8) & 0xff), UInt8((b2 >> 16) & 0xff), UInt8((b2 >> 24) & 0xff), UInt8(b3 & 0xff), UInt8((b3 >> 8) & 0xff), UInt8((b3 >> 16) & 0xff), UInt8((b3 >> 24) & 0xff) ] return result } } extension AES { private func expandKeyInv(_ key: Key, variant: Variant) -> Array> { let rounds = self.variantNr var rk2: Array> = self.expandKey(key, variant: variant) for r in 1.. Array> { func convertExpandedKey(_ expanded: Array) -> Array> { expanded.batched(by: 4).map({ UInt32(bytes: $0.reversed()) }).batched(by: 4).map { Array($0) } } /* * Function used in the Key Expansion routine that takes a four-byte * input word and applies an S-box to each of the four bytes to * produce an output word. */ func subWord(_ word: Array) -> Array { precondition(word.count == 4) var result = word for i in 0..<4 { result[i] = UInt8(self.sBox[Int(word[i])]) } return result } @inline(__always) func subWordInPlace(_ word: inout Array) { precondition(word.count == 4) word[0] = UInt8(self.sBox[Int(word[0])]) word[1] = UInt8(self.sBox[Int(word[1])]) word[2] = UInt8(self.sBox[Int(word[2])]) word[3] = UInt8(self.sBox[Int(word[3])]) } let wLength = self.variantNb * (self.variantNr + 1) * 4 let w = UnsafeMutablePointer.allocate(capacity: wLength) w.initialize(repeating: 0, count: wLength) defer { w.deinitialize(count: wLength) w.deallocate() } for i in 0.. for i in self.variantNk..(repeating: 0, count: 4) for wordIdx in 0..<4 { tmp[wordIdx] = w[4 * (i - 1) + wordIdx] } if (i % self.variantNk) == 0 { tmp = subWord(rotateLeft(UInt32(bytes: tmp), by: 8).bytes(totalBytes: 4)) tmp[0] = tmp.first! ^ AES.Rcon[i / variantNk] } else if self.variantNk > 6 && (i % self.variantNk) == 4 { subWordInPlace(&tmp) } // xor array of bytes for wordIdx in 0..<4 { w[4 * i + wordIdx] = w[4 * (i - variantNk) + wordIdx] ^ tmp[wordIdx] } } return convertExpandedKey(Array(UnsafeBufferPointer(start: w, count: wLength))) } @inline(__always) private func B0(_ x: UInt32) -> UInt32 { x & 0xff } @inline(__always) private func B1(_ x: UInt32) -> UInt32 { (x >> 8) & 0xff } @inline(__always) private func B2(_ x: UInt32) -> UInt32 { (x >> 16) & 0xff } @inline(__always) private func B3(_ x: UInt32) -> UInt32 { (x >> 24) & 0xff } @inline(__always) @usableFromInline internal func F1(_ x0: UInt32, _ x1: UInt32, _ x2: UInt32, _ x3: UInt32) -> UInt32 { var result: UInt32 = 0 result |= UInt32(self.B1(AES.T0[Int(x0 & 255)])) result |= UInt32(self.B1(AES.T0[Int((x1 >> 8) & 255)])) << 8 result |= UInt32(self.B1(AES.T0[Int((x2 >> 16) & 255)])) << 16 result |= UInt32(self.B1(AES.T0[Int(x3 >> 24)])) << 24 return result } private func calculateSBox() -> (sBox: Array, invSBox: Array) { let sboxLength = 256 let sbox = UnsafeMutablePointer.allocate(capacity: sboxLength) let invsbox = UnsafeMutablePointer.allocate(capacity: sboxLength) sbox.initialize(repeating: 0, count: sboxLength) invsbox.initialize(repeating: 0, count: sboxLength) defer { sbox.deinitialize(count: sboxLength) sbox.deallocate() invsbox.deinitialize(count: sboxLength) invsbox.deallocate() } sbox[0] = 0x63 var p: UInt8 = 1, q: UInt8 = 1 repeat { p = p ^ (UInt8(truncatingIfNeeded: Int(p) << 1) ^ ((p & 0x80) == 0x80 ? 0x1b : 0)) q ^= q << 1 q ^= q << 2 q ^= q << 4 q ^= (q & 0x80) == 0x80 ? 0x09 : 0 let s = 0x63 ^ q ^ rotateLeft(q, by: 1) ^ rotateLeft(q, by: 2) ^ rotateLeft(q, by: 3) ^ rotateLeft(q, by: 4) sbox[Int(p)] = UInt32(s) invsbox[Int(s)] = UInt32(p) } while p != 1 return (sBox: Array(UnsafeBufferPointer(start: sbox, count: sboxLength)), invSBox: Array(UnsafeBufferPointer(start: invsbox, count: sboxLength))) } } // MARK: Cipher extension AES: Cipher { @inlinable public func encrypt(_ bytes: ArraySlice) throws -> Array { let blockSize = self.blockMode.customBlockSize ?? AES.blockSize let chunks = bytes.batched(by: blockSize) var oneTimeCryptor = try makeEncryptor() var out = Array(reserveCapacity: bytes.count) for chunk in chunks { out += try oneTimeCryptor.update(withBytes: chunk, isLast: false) } // Padding may be added at the very end out += try oneTimeCryptor.finish() if self.blockMode.options.contains(.paddingRequired) && (out.count % AES.blockSize != 0) { throw Error.dataPaddingRequired } return out } @inlinable public func decrypt(_ bytes: ArraySlice) throws -> Array { if self.blockMode.options.contains(.paddingRequired) && (bytes.count % AES.blockSize != 0) { throw Error.dataPaddingRequired } var oneTimeCryptor = try makeDecryptor() let chunks = bytes.batched(by: AES.blockSize) if chunks.isEmpty { throw Error.invalidData } var out = Array(reserveCapacity: bytes.count) var lastIdx = chunks.startIndex chunks.indices.formIndex(&lastIdx, offsetBy: chunks.count - 1) // To properly remove padding, `isLast` has to be known when called with the last chunk of ciphertext // Last chunk of ciphertext may contains padded data so next call to update(..) won't be able to remove it for idx in chunks.indices { out += try oneTimeCryptor.update(withBytes: chunks[idx], isLast: idx == lastIdx) } return out } } ================================================ FILE: Sources/CryptoSwift/ASN1/ASN1.swift ================================================ // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // ASN1 Code inspired by Asn1Parser.swift from SwiftyRSA import Foundation /// A Partial ASN.1 (Abstract Syntax Notation 1) Encoder & Decoder Implementation. /// /// - Note: This implementation is limited to a few core types and is not an exhaustive / complete ASN1 implementation /// - Warning: This implementation has been developed for encoding and decoding DER & PEM files specifically. If you're using this Encoder/Decoder on other ASN1 structures, make sure you test the expected behavior appropriately. enum ASN1 { internal enum IDENTIFIERS: UInt8, Equatable { case SEQUENCE = 0x30 case INTERGER = 0x02 case OBJECTID = 0x06 case NULL = 0x05 case BITSTRING = 0x03 case OCTETSTRING = 0x04 static func == (lhs: UInt8, rhs: IDENTIFIERS) -> Bool { lhs == rhs.rawValue } var bytes: [UInt8] { switch self { case .NULL: return [self.rawValue, 0x00] default: return [self.rawValue] } } } /// An ASN1 node internal enum Node: CustomStringConvertible { /// An array of more `ASN1.Node`s case sequence(nodes: [Node]) /// An integer /// - Note: This ASN1 Encoder makes no assumptions about the sign and bit order of the integers passed in. The conversion from Integer to Data is your responsibility. case integer(data: Data) /// An objectIdentifier case objectIdentifier(data: Data) /// A null object case null /// A bitString case bitString(data: Data) /// An octetString case octetString(data: Data) var description: String { ASN1.printNode(self, level: 0) } } internal static func printNode(_ node: ASN1.Node, level: Int) -> String { var str: [String] = [] let prefix = String(repeating: "\t", count: level) switch node { case .integer(let int): str.append("\(prefix)Integer: \(int.toHexString())") case .bitString(let bs): str.append("\(prefix)BitString: \(bs.toHexString())") case .null: str.append("\(prefix)NULL") case .objectIdentifier(let oid): str.append("\(prefix)ObjectID: \(oid.toHexString())") case .octetString(let os): str.append("\(prefix)OctetString: \(os.toHexString())") case .sequence(let nodes): str.append("\(prefix)Sequence:") nodes.forEach { str.append(printNode($0, level: level + 1)) } } return str.joined(separator: "\n") } } ================================================ FILE: Sources/CryptoSwift/ASN1/ASN1Decoder.swift ================================================ // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // ASN1 Code inspired by Asn1Parser.swift from SwiftyRSA import Foundation extension ASN1 { /// A simple ASN1 parser that will recursively iterate over a root node and return a Node tree. /// The root node can be any of the supported nodes described in `Node`. If the parser encounters a sequence /// it will recursively parse its children. enum Decoder { enum DecodingError: Error { case noType case invalidType(value: UInt8) } /// Parses ASN1 data and returns its root node. /// /// - Parameter data: ASN1 data to parse /// - Returns: Root ASN1 Node /// - Throws: A DecodingError if anything goes wrong, or if an unknown node was encountered static func decode(data: Data) throws -> Node { let scanner = ASN1.Scanner(data: data) let node = try decodeNode(scanner: scanner) return node } /// Parses an ASN1 given an existing scanner. /// @warning: this will modify the state (ie: position) of the provided scanner. /// /// - Parameter scanner: Scanner to use to consume the data /// - Returns: Parsed node /// - Throws: A DecodingError if anything goes wrong, or if an unknown node was encountered private static func decodeNode(scanner: ASN1.Scanner) throws -> Node { let firstByte = try scanner.consume(length: 1).firstByte switch firstByte { case IDENTIFIERS.SEQUENCE.rawValue: let length = try scanner.consumeLength() let data = try scanner.consume(length: length) let nodes = try decodeSequence(data: data) return .sequence(nodes: nodes) case IDENTIFIERS.INTERGER.rawValue: let length = try scanner.consumeLength() let data = try scanner.consume(length: length) return .integer(data: data) case IDENTIFIERS.OBJECTID.rawValue: let length = try scanner.consumeLength() let data = try scanner.consume(length: length) return .objectIdentifier(data: data) case IDENTIFIERS.NULL.rawValue: _ = try scanner.consume(length: 1) return .null case IDENTIFIERS.BITSTRING.rawValue: let length = try scanner.consumeLength() // There's an extra byte (0x00) after the bit string length in all the keys I've encountered. // I couldn't find a specification that referenced this extra byte, but let's consume it and discard it. _ = try scanner.consume(length: 1) let data = try scanner.consume(length: length - 1) return .bitString(data: data) case IDENTIFIERS.OCTETSTRING.rawValue: let length = try scanner.consumeLength() let data = try scanner.consume(length: length) return .octetString(data: data) default: throw DecodingError.invalidType(value: firstByte) } } /// Parses an ASN1 sequence and returns its child nodes /// /// - Parameter data: ASN1 data /// - Returns: A list of ASN1 nodes /// - Throws: A DecodingError if anything goes wrong, or if an unknown node was encountered private static func decodeSequence(data: Data) throws -> [Node] { let scanner = ASN1.Scanner(data: data) var nodes: [Node] = [] while !scanner.isComplete { let node = try decodeNode(scanner: scanner) nodes.append(node) } return nodes } } } ================================================ FILE: Sources/CryptoSwift/ASN1/ASN1Encoder.swift ================================================ // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // ASN1 Code inspired by Asn1Parser.swift from SwiftyRSA import Foundation extension ASN1 { enum Encoder { /// Encodes an ASN1Node into it's byte representation /// /// - Parameter node: The Node to encode /// - Returns: The encoded bytes as a UInt8 array /// /// - Warning: This ASN.1 encoder has only been tested to work on certain ASN.1 data structures such as DER and PEM files. Before using this encoder for another application, ensure you test it's behavior accordingly. /// - Warning: This encoder makes no assumptions regarding Integer bit layout and signage. The proper serialization of Integers is left up to the user. public static func encode(_ node: ASN1.Node) -> [UInt8] { switch node { case .integer(let integer): return IDENTIFIERS.INTERGER.bytes + self.asn1LengthPrefixed(integer.byteArray) case .bitString(let bits): return IDENTIFIERS.BITSTRING.bytes + self.asn1LengthPrefixed([0x00] + bits.byteArray) case .octetString(let octet): return IDENTIFIERS.OCTETSTRING.bytes + self.asn1LengthPrefixed(octet.byteArray) case .null: return IDENTIFIERS.NULL.bytes case .objectIdentifier(let oid): return IDENTIFIERS.OBJECTID.bytes + self.asn1LengthPrefixed(oid.byteArray) case .sequence(let nodes): return IDENTIFIERS.SEQUENCE.bytes + self.asn1LengthPrefixed( nodes.reduce(into: Array(), { partialResult, node in partialResult += encode(node) })) } } /// Calculates and returns the ASN.1 length Prefix for a chunk of data /// /// - Parameter bytes: The bytes to be length prefixed /// - Returns: The ASN.1 length Prefix for this chuck of data (excluding the passed in data) private static func asn1LengthPrefix(_ bytes: [UInt8]) -> [UInt8] { if bytes.count >= 0x80 { var lengthAsBytes = withUnsafeBytes(of: bytes.count.bigEndian, Array.init) while lengthAsBytes.first == 0 { lengthAsBytes.removeFirst() } return [0x80 + UInt8(lengthAsBytes.count)] + lengthAsBytes } else { return [UInt8(bytes.count)] } } /// Prefixes the provided bytes with the appropriate ASN.1 length prefix /// /// - Parameter bytes: The bytes to be length prefixed /// - Returns: The provided bytes with the appropriate ASN.1 length prefix prepended private static func asn1LengthPrefixed(_ bytes: [UInt8]) -> [UInt8] { self.asn1LengthPrefix(bytes) + bytes } } } ================================================ FILE: Sources/CryptoSwift/ASN1/ASN1Scanner.swift ================================================ // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // ASN1 Scanner code is from Asn1Parser.swift from SwiftyRSA import Foundation extension ASN1 { /// Simple data scanner that consumes bytes from a raw data and keeps an updated position. internal class Scanner { enum ScannerError: Error { case outOfBounds } let data: Data var index: Int = 0 /// Returns whether there is no more data to consume var isComplete: Bool { return self.index >= self.data.count } /// Creates a scanner with provided data /// /// - Parameter data: Data to consume init(data: Data) { self.data = data } /// Consumes data of provided length and returns it /// /// - Parameter length: length of the data to consume /// - Returns: data consumed /// - Throws: ScannerError.outOfBounds error if asked to consume too many bytes func consume(length: Int) throws -> Data { guard length > 0 else { return Data() } guard self.index + length <= self.data.count else { throw ScannerError.outOfBounds } let subdata = self.data.subdata(in: self.index.. Int { let lengthByte = try consume(length: 1).firstByte // If the first byte's value is less than 0x80, it directly contains the length // so we can return it guard lengthByte >= 0x80 else { return Int(lengthByte) } // If the first byte's value is more than 0x80, it indicates how many following bytes // will describe the length. For instance, 0x85 indicates that 0x85 - 0x80 = 0x05 = 5 // bytes will describe the length, so we need to read the 5 next bytes and get their integer // value to determine the length. let nextByteCount = lengthByte - 0x80 let length = try consume(length: Int(nextByteCount)) return length.integer } } } internal extension Data { /// Returns the first byte of the current data var firstByte: UInt8 { var byte: UInt8 = 0 copyBytes(to: &byte, count: MemoryLayout.size) return byte } /// Returns the integer value of the current data. /// - Warning: This only supports data up to 4 bytes, as we can only extract 32-bit integers. var integer: Int { guard count > 0 else { return 0 } var int: UInt32 = 0 var offset: Int32 = Int32(count - 1) forEach { byte in let byte32 = UInt32(byte) let shifted = byte32 << (UInt32(offset) * 8) int = int | shifted offset -= 1 } return Int(int) } } ================================================ FILE: Sources/CryptoSwift/Array+Extension.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // extension Array { @inlinable init(reserveCapacity: Int) { self = Array() self.reserveCapacity(reserveCapacity) } @inlinable var slice: ArraySlice { self[self.startIndex ..< self.endIndex] } @inlinable subscript (safe index: Index) -> Element? { return indices.contains(index) ? self[index] : nil } } extension Array where Element == UInt8 { public init(hex: String) { self.init(reserveCapacity: hex.unicodeScalars.lazy.underestimatedCount) var buffer: UInt8? var skip = hex.hasPrefix("0x") ? 2 : 0 for char in hex.unicodeScalars.lazy { guard skip == 0 else { skip -= 1 continue } guard char.value >= 48 && char.value <= 102 else { removeAll() return } let v: UInt8 let c: UInt8 = UInt8(char.value) switch c { case let c where c <= 57: v = c - 48 case let c where c >= 65 && c <= 70: v = c - 55 case let c where c >= 97: v = c - 87 default: removeAll() return } if let b = buffer { append(b << 4 | v) buffer = nil } else { buffer = v } } if let b = buffer { append(b) } } public func toHexString() -> String { `lazy`.reduce(into: "") { var s = String($1, radix: 16) if s.count == 1 { s = "0" + s } $0 += s } } } extension Array where Element == UInt8 { /// split in chunks with given chunk size @available(*, deprecated) public func chunks(size chunksize: Int) -> Array> { var words = Array>() words.reserveCapacity(count / chunksize) for idx in stride(from: chunksize, through: count, by: chunksize) { words.append(Array(self[idx - chunksize ..< idx])) // slow for large table } let remainder = suffix(count % chunksize) if !remainder.isEmpty { words.append(Array(remainder)) } return words } public func md5() -> [Element] { Digest.md5(self) } public func sha1() -> [Element] { Digest.sha1(self) } public func sha224() -> [Element] { Digest.sha224(self) } public func sha256() -> [Element] { Digest.sha256(self) } public func sha384() -> [Element] { Digest.sha384(self) } public func sha512() -> [Element] { Digest.sha512(self) } public func sha2(_ variant: SHA2.Variant) -> [Element] { Digest.sha2(self, variant: variant) } public func sha3(_ variant: SHA3.Variant) -> [Element] { Digest.sha3(self, variant: variant) } public func crc32(seed: UInt32? = nil, reflect: Bool = true) -> UInt32 { Checksum.crc32(self, seed: seed, reflect: reflect) } public func crc32c(seed: UInt32? = nil, reflect: Bool = true) -> UInt32 { Checksum.crc32c(self, seed: seed, reflect: reflect) } public func crc16(seed: UInt16? = nil) -> UInt16 { Checksum.crc16(self, seed: seed) } public func encrypt(cipher: Cipher) throws -> [Element] { try cipher.encrypt(self.slice) } public func decrypt(cipher: Cipher) throws -> [Element] { try cipher.decrypt(self.slice) } public func authenticate(with authenticator: A) throws -> [Element] { try authenticator.authenticate(self) } } ================================================ FILE: Sources/CryptoSwift/Authenticator.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // /// Message authentication code. public protocol Authenticator { /// Calculate Message Authentication Code (MAC) for message. func authenticate(_ bytes: Array) throws -> Array } ================================================ FILE: Sources/CryptoSwift/BatchedCollection.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // @usableFromInline struct BatchedCollectionIndex { let range: Range } extension BatchedCollectionIndex: Comparable { @usableFromInline static func == (lhs: BatchedCollectionIndex, rhs: BatchedCollectionIndex) -> Bool { lhs.range.lowerBound == rhs.range.lowerBound } @usableFromInline static func < (lhs: BatchedCollectionIndex, rhs: BatchedCollectionIndex) -> Bool { lhs.range.lowerBound < rhs.range.lowerBound } } protocol BatchedCollectionType: Collection { associatedtype Base: Collection } @usableFromInline struct BatchedCollection: Collection { let base: Base let size: Int @usableFromInline init(base: Base, size: Int) { self.base = base self.size = size } @usableFromInline typealias Index = BatchedCollectionIndex private func nextBreak(after idx: Base.Index) -> Base.Index { self.base.index(idx, offsetBy: self.size, limitedBy: self.base.endIndex) ?? self.base.endIndex } @usableFromInline var startIndex: Index { Index(range: self.base.startIndex.. Index { Index(range: idx.range.upperBound.. Base.SubSequence { self.base[idx.range] } } extension Collection { @inlinable func batched(by size: Int) -> BatchedCollection { BatchedCollection(base: self, size: size) } } ================================================ FILE: Sources/CryptoSwift/Bit.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public enum Bit: Int { case zero case one } extension Bit { @inlinable func inverted() -> Bit { self == .zero ? .one : .zero } } ================================================ FILE: Sources/CryptoSwift/BlockCipher.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // protocol BlockCipher: Cipher { static var blockSize: Int { get } } ================================================ FILE: Sources/CryptoSwift/BlockDecryptor.swift ================================================ // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public class BlockDecryptor: Cryptor, Updatable { public enum Error: Swift.Error { case unsupported } @usableFromInline let blockSize: Int @usableFromInline let padding: Padding @usableFromInline var worker: CipherModeWorker @usableFromInline var accumulated = Array() @usableFromInline init(blockSize: Int, padding: Padding, _ worker: CipherModeWorker) throws { self.blockSize = blockSize self.padding = padding self.worker = worker } @inlinable public func update(withBytes bytes: ArraySlice, isLast: Bool = false) throws -> Array { self.accumulated += bytes // If a worker (eg GCM) can combine ciphertext + tag // we need to remove tag from the ciphertext. if !isLast && self.accumulated.count < self.blockSize + self.worker.additionalBufferSize { return [] } let accumulatedWithoutSuffix: Array if self.worker.additionalBufferSize > 0 { // FIXME: how slow is that? accumulatedWithoutSuffix = Array(self.accumulated.prefix(self.accumulated.count - self.worker.additionalBufferSize)) } else { accumulatedWithoutSuffix = self.accumulated } var processedBytesCount = 0 var plaintext = Array(reserveCapacity: accumulatedWithoutSuffix.count) // Processing in a block-size manner. It's good for block modes, but bad for stream modes. for var chunk in accumulatedWithoutSuffix.batched(by: self.blockSize) { if isLast || (accumulatedWithoutSuffix.count - processedBytesCount) >= blockSize { let isLastChunk = processedBytesCount + chunk.count == accumulatedWithoutSuffix.count if isLast, isLastChunk, var finalizingWorker = worker as? FinalizingDecryptModeWorker { chunk = try finalizingWorker.willDecryptLast(bytes: chunk + accumulated.suffix(worker.additionalBufferSize)) // tag size } if !chunk.isEmpty { plaintext += worker.decrypt(block: chunk) } if isLast, isLastChunk, var finalizingWorker = worker as? FinalizingDecryptModeWorker { plaintext = Array(try finalizingWorker.didDecryptLast(bytes: plaintext.slice)) } processedBytesCount += chunk.count } } accumulated.removeFirst(processedBytesCount) // super-slow if isLast { if accumulatedWithoutSuffix.isEmpty, var finalizingWorker = worker as? FinalizingDecryptModeWorker { try finalizingWorker.willDecryptLast(bytes: self.accumulated.suffix(self.worker.additionalBufferSize)) plaintext = Array(try finalizingWorker.didDecryptLast(bytes: plaintext.slice)) } plaintext = self.padding.remove(from: plaintext, blockSize: self.blockSize) } return plaintext } public func seek(to position: Int) throws { guard var worker = self.worker as? SeekableModeWorker else { throw Error.unsupported } try worker.seek(to: position) self.worker = worker accumulated = [] } } ================================================ FILE: Sources/CryptoSwift/BlockEncryptor.swift ================================================ // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // @usableFromInline final class BlockEncryptor: Cryptor, Updatable { public enum Error: Swift.Error { case unsupported } private let blockSize: Int private var worker: CipherModeWorker private let padding: Padding // Accumulated bytes. Not all processed bytes. private var accumulated = Array(reserveCapacity: 16) private var lastBlockRemainder = 0 @usableFromInline init(blockSize: Int, padding: Padding, _ worker: CipherModeWorker) throws { self.blockSize = blockSize self.padding = padding self.worker = worker } // MARK: Updatable public func update(withBytes bytes: ArraySlice, isLast: Bool) throws -> Array { self.accumulated += bytes if isLast { self.accumulated = self.padding.add(to: self.accumulated, blockSize: self.blockSize) } var encrypted = Array(reserveCapacity: accumulated.count) for chunk in self.accumulated.batched(by: self.blockSize) { if isLast || chunk.count == self.blockSize { encrypted += self.worker.encrypt(block: chunk) } } // Stream encrypts all, so it removes all elements self.accumulated.removeFirst(encrypted.count) if var finalizingWorker = worker as? FinalizingEncryptModeWorker, isLast == true { encrypted = Array(try finalizingWorker.finalize(encrypt: encrypted.slice)) } return encrypted } @usableFromInline func seek(to: Int) throws { throw Error.unsupported } } ================================================ FILE: Sources/CryptoSwift/BlockMode/BlockMode.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public typealias CipherOperationOnBlock = (_ block: ArraySlice) -> Array? public protocol BlockMode { var options: BlockModeOption { get } //TODO: doesn't have to be public @inlinable func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker var customBlockSize: Int? { get } } typealias StreamMode = BlockMode ================================================ FILE: Sources/CryptoSwift/BlockMode/BlockModeOptions.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public struct BlockModeOption: OptionSet { public let rawValue: Int public init(rawValue: Int) { self.rawValue = rawValue } @usableFromInline static let none = BlockModeOption(rawValue: 1 << 0) @usableFromInline static let initializationVectorRequired = BlockModeOption(rawValue: 1 << 1) @usableFromInline static let paddingRequired = BlockModeOption(rawValue: 1 << 2) @usableFromInline static let useEncryptToDecrypt = BlockModeOption(rawValue: 1 << 3) } ================================================ FILE: Sources/CryptoSwift/BlockMode/CBC.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // Cipher-block chaining (CBC) // public struct CBC: BlockMode { public enum Error: Swift.Error { /// Invalid IV case invalidInitializationVector } public let options: BlockModeOption = [.initializationVectorRequired, .paddingRequired] private let iv: Array public let customBlockSize: Int? = nil public init(iv: Array) { self.iv = iv } public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { if self.iv.count != blockSize { throw Error.invalidInitializationVector } return CBCModeWorker(blockSize: blockSize, iv: self.iv.slice, cipherOperation: cipherOperation) } } struct CBCModeWorker: BlockModeWorker { let cipherOperation: CipherOperationOnBlock var blockSize: Int let additionalBufferSize: Int = 0 private let iv: ArraySlice private var prev: ArraySlice? @inlinable init(blockSize: Int, iv: ArraySlice, cipherOperation: @escaping CipherOperationOnBlock) { self.blockSize = blockSize self.iv = iv self.cipherOperation = cipherOperation } @inlinable mutating func encrypt(block plaintext: ArraySlice) -> Array { guard let ciphertext = cipherOperation(xor(prev ?? iv, plaintext)) else { return Array(plaintext) } self.prev = ciphertext.slice return ciphertext } @inlinable mutating func decrypt(block ciphertext: ArraySlice) -> Array { guard let plaintext = cipherOperation(ciphertext) else { return Array(ciphertext) } let result: Array = xor(prev ?? self.iv, plaintext) self.prev = ciphertext return result } } ================================================ FILE: Sources/CryptoSwift/BlockMode/CCM.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // CCM mode combines the well known CBC-MAC with the well known counter mode of encryption. // https://tools.ietf.org/html/rfc3610 // https://csrc.nist.gov/publications/detail/sp/800-38c/final #if canImport(Darwin) import Darwin #elseif canImport(Android) import Android #elseif canImport(Glibc) import Glibc #elseif canImport(Musl) import Musl #elseif canImport(ucrt) import ucrt #elseif canImport(WASILibc) import WASILibc #endif /// Counter with Cipher Block Chaining-Message Authentication Code public struct CCM: StreamMode { public enum Error: Swift.Error { /// Invalid IV case invalidInitializationVector case invalidParameter case fail } public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt] private let nonce: Array private let additionalAuthenticatedData: Array? private let tagLength: Int private let messageLength: Int // total message length. need to know in advance public let customBlockSize: Int? = nil // `authenticationTag` nil for encryption, known tag for decryption /// For encryption, the value is set at the end of the encryption. /// For decryption, this is a known Tag to validate against. public var authenticationTag: Array? /// Initialize CCM /// /// - Parameters: /// - iv: Initialization vector. Nonce. Valid length between 7 and 13 bytes. /// - tagLength: Authentication tag length, in bytes. Value of {4, 6, 8, 10, 12, 14, 16}. /// - messageLength: Plaintext message length (excluding tag if attached). Length have to be provided in advance. /// - additionalAuthenticatedData: Additional authenticated data. public init(iv: Array, tagLength: Int, messageLength: Int, additionalAuthenticatedData: Array? = nil) { self.nonce = iv self.tagLength = tagLength self.additionalAuthenticatedData = additionalAuthenticatedData self.messageLength = messageLength // - tagLength } /// Initialize CCM /// /// - Parameters: /// - iv: Initialization vector. Nonce. Valid length between 7 and 13 bytes. /// - tagLength: Authentication tag length, in bytes. Value of {4, 6, 8, 10, 12, 14, 16}. /// - messageLength: Plaintext message length (excluding tag if attached). Length have to be provided in advance. /// - authenticationTag: Authentication Tag value if not concatenated to ciphertext. /// - additionalAuthenticatedData: Additional authenticated data. public init(iv: Array, tagLength: Int, messageLength: Int, authenticationTag: Array, additionalAuthenticatedData: Array? = nil) { self.init(iv: iv, tagLength: tagLength, messageLength: messageLength, additionalAuthenticatedData: additionalAuthenticatedData) self.authenticationTag = authenticationTag } public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { if self.nonce.isEmpty { throw Error.invalidInitializationVector } return CCMModeWorker(blockSize: blockSize, nonce: self.nonce.slice, messageLength: self.messageLength, additionalAuthenticatedData: self.additionalAuthenticatedData, tagLength: self.tagLength, cipherOperation: cipherOperation) } } class CCMModeWorker: StreamModeWorker, SeekableModeWorker, CounterModeWorker, FinalizingEncryptModeWorker, FinalizingDecryptModeWorker { typealias Counter = Int var counter = 0 let cipherOperation: CipherOperationOnBlock let blockSize: Int private let tagLength: Int private let messageLength: Int // total message length. need to know in advance private let q: UInt8 let additionalBufferSize: Int private var keystreamPosIdx = 0 private let nonce: Array private var last_y: ArraySlice = [] private var keystream: Array = [] // Known Tag used to validate during decryption private var expectedTag: Array? public enum Error: Swift.Error { case invalidParameter } init(blockSize: Int, nonce: ArraySlice, messageLength: Int, additionalAuthenticatedData: [UInt8]?, expectedTag: Array? = nil, tagLength: Int, cipherOperation: @escaping CipherOperationOnBlock) { self.blockSize = 16 // CCM is defined for 128 block size self.tagLength = tagLength self.additionalBufferSize = tagLength self.messageLength = messageLength self.expectedTag = expectedTag self.cipherOperation = cipherOperation self.nonce = Array(nonce) self.q = UInt8(15 - nonce.count) // n = 15-q let hasAssociatedData = additionalAuthenticatedData != nil && !additionalAuthenticatedData!.isEmpty self.processControlInformation(nonce: self.nonce, tagLength: tagLength, hasAssociatedData: hasAssociatedData) if let aad = additionalAuthenticatedData, hasAssociatedData { self.process(aad: aad) } } // For the very first time setup new IV (aka y0) from the block0 private func processControlInformation(nonce: [UInt8], tagLength: Int, hasAssociatedData: Bool) { let block0 = try! format(nonce: nonce, Q: UInt32(self.messageLength), q: self.q, t: UInt8(tagLength), hasAssociatedData: hasAssociatedData).slice let y0 = self.cipherOperation(block0)!.slice self.last_y = y0 } private func process(aad: [UInt8]) { let encodedAAD = format(aad: aad) for block_i in encodedAAD.batched(by: 16) { let y_i = self.cipherOperation(xor(block_i, self.last_y))!.slice self.last_y = y_i } } private func S(i: Int) throws -> [UInt8] { let ctr = try format(counter: i, nonce: nonce, q: q) return self.cipherOperation(ctr.slice)! } @inlinable func seek(to position: Int) throws { self.counter = position self.keystream = try self.S(i: position) let offset = position % self.blockSize self.keystreamPosIdx = offset } func encrypt(block plaintext: ArraySlice) -> Array { var result = Array(reserveCapacity: plaintext.count) var processed = 0 while processed < plaintext.count { // Need a full block here to update keystream and do CBC if self.keystream.isEmpty || self.keystreamPosIdx == self.blockSize { // y[i], where i is the counter. Can encrypt 1 block at a time self.counter += 1 guard let S = try? S(i: counter) else { return Array(plaintext) } let plaintextP = addPadding(Array(plaintext), blockSize: blockSize) guard let y = cipherOperation(xor(last_y, plaintextP)) else { return Array(plaintext) } self.last_y = y.slice self.keystream = S self.keystreamPosIdx = 0 } let xored: Array = xor(plaintext[plaintext.startIndex.advanced(by: processed)...], keystream[keystreamPosIdx...]) keystreamPosIdx += xored.count processed += xored.count result += xored } return result } @inlinable func finalize(encrypt ciphertext: ArraySlice) throws -> ArraySlice { // concatenate T at the end guard let S0 = try? S(i: 0) else { return ciphertext } let computedTag = xor(last_y.prefix(self.tagLength), S0) as ArraySlice return ciphertext + computedTag } // Decryption is stream // CBC is block private var accumulatedPlaintext: [UInt8] = [] func decrypt(block ciphertext: ArraySlice) -> Array { var output = Array(reserveCapacity: ciphertext.count) do { var currentCounter = self.counter var processed = 0 while processed < ciphertext.count { // Need a full block here to update keystream and do CBC // New keystream for a new block if self.keystream.isEmpty || self.keystreamPosIdx == self.blockSize { currentCounter += 1 guard let S = try? S(i: currentCounter) else { return Array(ciphertext) } self.keystream = S self.keystreamPosIdx = 0 } let xored: Array = xor(ciphertext[ciphertext.startIndex.advanced(by: processed)...], keystream[keystreamPosIdx...]) // plaintext keystreamPosIdx += xored.count processed += xored.count output += xored self.counter = currentCounter } } // Accumulate plaintext for the MAC calculations at the end. // It would be good to process it together though, here. self.accumulatedPlaintext += output // Shouldn't return plaintext until validate tag. // With incremental update, can't validate tag until all block are processed. return output } @inlinable func finalize(decrypt plaintext: ArraySlice) throws -> ArraySlice { // concatenate T at the end let computedTag = Array(last_y.prefix(self.tagLength)) guard let expectedTag = self.expectedTag, expectedTag == computedTag else { throw CCM.Error.fail } return plaintext } @discardableResult func willDecryptLast(bytes ciphertext: ArraySlice) throws -> ArraySlice { // get tag of additionalBufferSize size // `ciphertext` contains at least additionalBufferSize bytes // overwrite expectedTag property used later for verification guard let S0 = try? S(i: 0) else { return ciphertext } self.expectedTag = xor(ciphertext.suffix(self.tagLength), S0) as [UInt8] return ciphertext[ciphertext.startIndex..) throws -> ArraySlice { // Calculate Tag, from the last CBC block, for accumulated plaintext. var processed = 0 for block in self.accumulatedPlaintext.batched(by: self.blockSize) { let blockP = addPadding(Array(block), blockSize: blockSize) guard let y = cipherOperation(xor(last_y, blockP)) else { return plaintext } self.last_y = y.slice processed += block.count } self.accumulatedPlaintext.removeFirst(processed) return plaintext } } // Q - octet length of P // q - octet length of Q. Maximum length (in octets) of payload. An element of {2,3,4,5,6,7,8} // t - octet length of T (MAC length). An element of {4,6,8,10,12,14,16} private func format(nonce N: [UInt8], Q: UInt32, q: UInt8, t: UInt8, hasAssociatedData: Bool) throws -> [UInt8] { var flags0: UInt8 = 0 if hasAssociatedData { // 7 bit flags0 |= (1 << 6) } // 6,5,4 bit is t in 3 bits flags0 |= (((t - 2) / 2) & 0x07) << 3 // 3,2,1 bit is q in 3 bits flags0 |= ((q - 1) & 0x07) << 0 var block0: [UInt8] = Array(repeating: 0, count: 16) block0[0] = flags0 // N in 1...(15-q) octets, n = 15-q // n is an element of {7,8,9,10,11,12,13} let n = 15 - Int(q) guard (n + Int(q)) == 15 else { // n+q == 15 throw CCMModeWorker.Error.invalidParameter } block0[1...n] = N[0...(n - 1)] // Q in (16-q)...15 octets block0[(16 - Int(q))...15] = Q.bytes(totalBytes: Int(q)).slice return block0 } /// Formatting of the Counter Blocks. Ctr[i] /// The counter generation function. /// Q - octet length of P /// q - octet length of Q. Maximum length (in octets) of payload. An element of {2,3,4,5,6,7,8} private func format(counter i: Int, nonce N: [UInt8], q: UInt8) throws -> [UInt8] { var flags0: UInt8 = 0 // bit 8,7 is Reserved // bit 4,5,6 shall be set to 0 // 3,2,1 bit is q in 3 bits flags0 |= ((q - 1) & 0x07) << 0 var block = Array(repeating: 0, count: 16) // block[0] block[0] = flags0 // N in 1...(15-q) octets, n = 15-q // n is an element of {7,8,9,10,11,12,13} let n = 15 - Int(q) guard (n + Int(q)) == 15 else { // n+q == 15 throw CCMModeWorker.Error.invalidParameter } block[1...n] = N[0...(n - 1)] // [i]8q in (16-q)...15 octets block[(16 - Int(q))...15] = i.bytes(totalBytes: Int(q)).slice return block } /// Resulting can be partitioned into 16-octet blocks private func format(aad: [UInt8]) -> [UInt8] { let a = aad.count switch Double(a) { case 0..<65280: // 2^16-2^8 // [a]16 return addPadding(a.bytes(totalBytes: 2) + aad, blockSize: 16) case 65280..<4_294_967_296: // 2^32 // [a]32 return addPadding([0xFF, 0xFE] + a.bytes(totalBytes: 4) + aad, blockSize: 16) case 4_294_967_296.., blockSize: Int) -> Array { if bytes.isEmpty { return Array(repeating: 0, count: blockSize) } let remainder = bytes.count % blockSize if remainder == 0 { return bytes } let paddingCount = blockSize - remainder if paddingCount > 0 { return bytes + Array(repeating: 0, count: paddingCount) } return bytes } ================================================ FILE: Sources/CryptoSwift/BlockMode/CFB.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // Cipher feedback (CFB) // public struct CFB: BlockMode { public enum Error: Swift.Error { /// Invalid IV case invalidInitializationVector } public enum SegmentSize: Int { case cfb8 = 1 // Encrypt byte per byte case cfb128 = 16 // Encrypt 16 bytes per 16 bytes (default) } public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt] private let iv: Array private let segmentSize: SegmentSize public let customBlockSize: Int? public init(iv: Array, segmentSize: SegmentSize = .cfb128) { self.iv = iv self.segmentSize = segmentSize self.customBlockSize = segmentSize.rawValue } public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { if !(self.iv.count == blockSize || (segmentSize == .cfb8 && self.iv.count == AES.blockSize)) { throw Error.invalidInitializationVector } return CFBModeWorker(blockSize: blockSize, iv: self.iv.slice, segmentSize: segmentSize, cipherOperation: cipherOperation) } } struct CFBModeWorker: BlockModeWorker { let cipherOperation: CipherOperationOnBlock let blockSize: Int let additionalBufferSize: Int = 0 private let iv: ArraySlice private let segmentSize: CFB.SegmentSize private var prev: ArraySlice? init(blockSize: Int, iv: ArraySlice, segmentSize: CFB.SegmentSize, cipherOperation: @escaping CipherOperationOnBlock) { self.blockSize = blockSize self.iv = iv self.segmentSize = segmentSize self.cipherOperation = cipherOperation } @inlinable mutating func encrypt(block plaintext: ArraySlice) -> Array { switch segmentSize { case .cfb128: guard let ciphertext = cipherOperation(prev ?? iv) else { return Array(plaintext) } self.prev = xor(plaintext, ciphertext.slice) return Array(self.prev ?? []) case .cfb8: guard let ciphertext = cipherOperation(prev ?? iv) else { return Array(plaintext) } let result = [Array(plaintext)[0] ^ Array(ciphertext)[0]] self.prev = Array((prev ?? iv).dropFirst()) + [result[0]] return result } } @inlinable mutating func decrypt(block ciphertext: ArraySlice) -> Array { switch segmentSize { case .cfb128: guard let plaintext = cipherOperation(prev ?? iv) else { return Array(ciphertext) } let result: Array = xor(plaintext, ciphertext) prev = ciphertext return result case .cfb8: guard let plaintext = cipherOperation(prev ?? iv) else { return Array(ciphertext) } self.prev = Array((prev ?? iv).dropFirst()) + [Array(ciphertext)[0]] return [Array(ciphertext)[0] ^ Array(plaintext)[0]] } } } ================================================ FILE: Sources/CryptoSwift/BlockMode/CTR.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // Counter (CTR) public struct CTR: StreamMode { public enum Error: Swift.Error { /// Invalid IV case invalidInitializationVector } public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt] private let iv: Array private let counter: Int public let customBlockSize: Int? = nil public init(iv: Array, counter: Int = 0) { self.iv = iv self.counter = counter } public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { if self.iv.count != blockSize { throw Error.invalidInitializationVector } return CTRModeWorker(blockSize: blockSize, iv: self.iv.slice, counter: self.counter, cipherOperation: cipherOperation) } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// struct CTRModeWorker: StreamModeWorker, SeekableModeWorker, CounterModeWorker { typealias Counter = CTRCounter final class CTRCounter { private let constPrefix: Array private var value: UInt64 //TODO: make it an updatable value, computing is too slow var bytes: Array { self.constPrefix + self.value.bytes() } @inlinable init(_ initialValue: Array) { let halfIndex = initialValue.startIndex.advanced(by: initialValue.count / 2) self.constPrefix = Array(initialValue[initialValue.startIndex.., startAt index: Int) { self.init(buildCounterValue(nonce, counter: UInt64(index))) } static func += (lhs: CTRCounter, rhs: Int) { lhs.value += UInt64(rhs) } } let cipherOperation: CipherOperationOnBlock let additionalBufferSize: Int = 0 let iv: Array var counter: CTRCounter private let blockSize: Int // The same keystream is used for the block length plaintext // As new data is added, keystream suffix is used to xor operation. private var keystream: Array private var keystreamPosIdx = 0 init(blockSize: Int, iv: ArraySlice, counter: Int, cipherOperation: @escaping CipherOperationOnBlock) { self.cipherOperation = cipherOperation self.blockSize = blockSize self.iv = Array(iv) // the first keystream is calculated from the nonce = initial value of counter self.counter = CTRCounter(nonce: Array(iv), startAt: counter) self.keystream = Array(cipherOperation(self.counter.bytes.slice)!) } @inlinable mutating func seek(to position: Int) throws { let offset = position % self.blockSize self.counter = CTRCounter(nonce: self.iv, startAt: position / self.blockSize) self.keystream = Array(self.cipherOperation(self.counter.bytes.slice)!) self.keystreamPosIdx = offset } // plaintext is at most blockSize long @inlinable mutating func encrypt(block plaintext: ArraySlice) -> Array { var result = Array(reserveCapacity: plaintext.count) var processed = 0 while processed < plaintext.count { // Update keystream if self.keystreamPosIdx == self.blockSize { self.counter += 1 self.keystream = Array(self.cipherOperation(self.counter.bytes.slice)!) self.keystreamPosIdx = 0 } let xored: Array = xor(plaintext[plaintext.startIndex.advanced(by: processed)...], keystream[keystreamPosIdx...]) keystreamPosIdx += xored.count processed += xored.count result += xored } return result } mutating func decrypt(block ciphertext: ArraySlice) -> Array { self.encrypt(block: ciphertext) } } private func buildCounterValue(_ iv: Array, counter: UInt64) -> Array { let noncePartLen = iv.count / 2 let noncePrefix = iv[iv.startIndex.. // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public protocol CipherModeWorker { var cipherOperation: CipherOperationOnBlock { get } // Additional space needed when incrementally process data // eg. for GCM combined mode var additionalBufferSize: Int { get } @inlinable mutating func encrypt(block plaintext: ArraySlice) -> Array @inlinable mutating func decrypt(block ciphertext: ArraySlice) -> Array } /// Block workers use `BlockEncryptor` public protocol BlockModeWorker: CipherModeWorker { var blockSize: Int { get } } public protocol CounterModeWorker: CipherModeWorker { associatedtype Counter var counter: Counter { get set } } public protocol SeekableModeWorker: CipherModeWorker { mutating func seek(to position: Int) throws } /// Stream workers use `StreamEncryptor` public protocol StreamModeWorker: CipherModeWorker { } public protocol FinalizingEncryptModeWorker: CipherModeWorker { // Any final calculations, eg. calculate tag // Called after the last block is encrypted mutating func finalize(encrypt ciphertext: ArraySlice) throws -> ArraySlice } public protocol FinalizingDecryptModeWorker: CipherModeWorker { // Called before decryption, hence input is ciphertext. // ciphertext is either a last block, or a tag (for stream workers) @discardableResult mutating func willDecryptLast(bytes ciphertext: ArraySlice) throws -> ArraySlice // Called after decryption, hence input is ciphertext mutating func didDecryptLast(bytes plaintext: ArraySlice) throws -> ArraySlice // Any final calculations, eg. calculate tag // Called after the last block is encrypted mutating func finalize(decrypt plaintext: ArraySlice) throws -> ArraySlice } ================================================ FILE: Sources/CryptoSwift/BlockMode/ECB.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // Electronic codebook (ECB) // public struct ECB: BlockMode { public let options: BlockModeOption = .paddingRequired public let customBlockSize: Int? = nil public init() { } public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { ECBModeWorker(blockSize: blockSize, cipherOperation: cipherOperation) } } struct ECBModeWorker: BlockModeWorker { typealias Element = Array let cipherOperation: CipherOperationOnBlock let blockSize: Int let additionalBufferSize: Int = 0 init(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) { self.blockSize = blockSize self.cipherOperation = cipherOperation } @inlinable mutating func encrypt(block plaintext: ArraySlice) -> Array { guard let ciphertext = cipherOperation(plaintext) else { return Array(plaintext) } return ciphertext } mutating func decrypt(block ciphertext: ArraySlice) -> Array { self.encrypt(block: ciphertext) } } ================================================ FILE: Sources/CryptoSwift/BlockMode/GCM.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // Galois/Counter Mode (GCM) // https://csrc.nist.gov/publications/detail/sp/800-38d/final // ref: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.694.695&rep=rep1&type=pdf // public final class GCM: BlockMode { public enum Mode { /// In combined mode, the authentication tag is directly appended to the encrypted message. This is usually what you want. case combined /// Some applications may need to store the authentication tag and the encrypted message at different locations. case detached } public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt] public enum Error: Swift.Error { /// Invalid IV case invalidInitializationVector /// Special symbol FAIL that indicates that the inputs are not authentic. case fail } private let iv: Array private let additionalAuthenticatedData: Array? private let mode: Mode public let customBlockSize: Int? = nil /// Length of authentication tag, in bytes. /// For encryption, the value is given as init parameter. /// For decryption, the length of given authentication tag is used. private let tagLength: Int // `authenticationTag` nil for encryption, known tag for decryption /// For encryption, the value is set at the end of the encryption. /// For decryption, this is a known Tag to validate against. public var authenticationTag: Array? // encrypt /// Possible tag lengths: 4,8,12,13,14,15,16 public init(iv: Array, additionalAuthenticatedData: Array? = nil, tagLength: Int = 16, mode: Mode = .detached) { self.iv = iv self.additionalAuthenticatedData = additionalAuthenticatedData self.mode = mode self.tagLength = tagLength } // decrypt public convenience init(iv: Array, authenticationTag: Array, additionalAuthenticatedData: Array? = nil, mode: Mode = .detached) { self.init(iv: iv, additionalAuthenticatedData: additionalAuthenticatedData, tagLength: authenticationTag.count, mode: mode) self.authenticationTag = authenticationTag } public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { if self.iv.isEmpty { throw Error.invalidInitializationVector } let worker = GCMModeWorker(iv: iv.slice, aad: self.additionalAuthenticatedData?.slice, expectedTag: self.authenticationTag, tagLength: self.tagLength, mode: self.mode, cipherOperation: cipherOperation) worker.didCalculateTag = { [weak self] tag in self?.authenticationTag = tag } return worker } } // MARK: - Worker final class GCMModeWorker: BlockModeWorker, FinalizingEncryptModeWorker, FinalizingDecryptModeWorker { let cipherOperation: CipherOperationOnBlock // Callback called when authenticationTag is ready var didCalculateTag: ((Array) -> Void)? private let tagLength: Int // GCM nonce is 96-bits by default. It's the most effective length for the IV private static let nonceSize = 12 // GCM is designed for 128-bit ciphers like AES (but not really for Blowfish). 64-bit mode is not implemented. let blockSize = 16 // 128 bit let additionalBufferSize: Int private let iv: ArraySlice private let mode: GCM.Mode private var counter: UInt128 private let eky0: UInt128 // move to GF? private let h: UInt128 // Additional authenticated data private let aad: ArraySlice? // Known Tag used to validate during decryption private var expectedTag: Array? // Note: need new worker to reset instance // Use empty aad if not specified. AAD is optional. private lazy var gf: GF = { if let aad = aad { return GF(aad: Array(aad), h: h, blockSize: blockSize) } return GF(aad: [UInt8](), h: h, blockSize: blockSize) }() init(iv: ArraySlice, aad: ArraySlice? = nil, expectedTag: Array? = nil, tagLength: Int, mode: GCM.Mode, cipherOperation: @escaping CipherOperationOnBlock) { self.cipherOperation = cipherOperation self.iv = iv self.mode = mode self.aad = aad self.expectedTag = expectedTag self.tagLength = tagLength self.h = UInt128(cipherOperation(Array(repeating: 0, count: self.blockSize).slice)!) // empty block if mode == .combined { self.additionalBufferSize = tagLength } else { self.additionalBufferSize = 0 } // Assume nonce is 12 bytes long, otherwise initial counter would be calculated from GHASH // counter = GF.ghash(aad: [UInt8](), ciphertext: nonce) if iv.count == GCMModeWorker.nonceSize { self.counter = makeCounter(nonce: Array(self.iv)) } else { self.counter = GF.ghash(h: self.h, aad: [UInt8](), ciphertext: Array(iv), blockSize: self.blockSize) } // Set constants self.eky0 = UInt128(cipherOperation(self.counter.bytes.slice)!) } func encrypt(block plaintext: ArraySlice) -> Array { self.counter = incrementCounter(self.counter) guard let ekyN = cipherOperation(counter.bytes.slice) else { return Array(plaintext) } // plaintext block ^ ek1 let ciphertext = xor(plaintext, ekyN) as Array // update ghash incrementally gf.ghashUpdate(block: ciphertext) return Array(ciphertext) } @inlinable func finalize(encrypt ciphertext: ArraySlice) throws -> ArraySlice { // Calculate MAC tag. let ghash = self.gf.ghashFinish() let tag = Array((ghash ^ self.eky0).bytes.prefix(self.tagLength)) // Notify handler self.didCalculateTag?(tag) switch self.mode { case .combined: return (ciphertext + tag).slice case .detached: return ciphertext } } @inlinable func decrypt(block ciphertext: ArraySlice) -> Array { self.counter = incrementCounter(self.counter) // update ghash incrementally self.gf.ghashUpdate(block: Array(ciphertext)) guard let ekN = cipherOperation(counter.bytes.slice) else { return Array(ciphertext) } // ciphertext block ^ ek1 let plaintext = xor(ciphertext, ekN) as Array return plaintext } // The authenticated decryption operation has five inputs: K, IV , C, A, and T. It has only a single // output, either the plaintext value P or a special symbol FAIL that indicates that the inputs are not // authentic. @discardableResult func willDecryptLast(bytes ciphertext: ArraySlice) throws -> ArraySlice { // Validate tag switch self.mode { case .combined: // overwrite expectedTag property used later for verification self.expectedTag = Array(ciphertext.suffix(self.tagLength)) return ciphertext[ciphertext.startIndex..) throws -> ArraySlice { // Calculate MAC tag. let ghash = self.gf.ghashFinish() let computedTag = Array((ghash ^ self.eky0).bytes.prefix(self.tagLength)) // Validate tag guard let expectedTag = self.expectedTag, computedTag == expectedTag else { throw GCM.Error.fail } return plaintext } func finalize(decrypt plaintext: ArraySlice) throws -> ArraySlice { // do nothing plaintext } } // MARK: - Local utils private func makeCounter(nonce: Array) -> UInt128 { UInt128(nonce + [0, 0, 0, 1]) } // Successive counter values are generated using the function incr(), which treats the rightmost 32 // bits of its argument as a nonnegative integer with the least significant bit on the right private func incrementCounter(_ counter: UInt128) -> UInt128 { let b = counter.i.b + 1 let a = (b == 0 ? counter.i.a + 1 : counter.i.a) return UInt128((a, b)) } // If data is not a multiple of block size bytes long then the remainder is zero padded // Note: It's similar to ZeroPadding, but it's not the same. private func addPadding(_ bytes: Array, blockSize: Int) -> Array { if bytes.isEmpty { return Array(repeating: 0, count: blockSize) } let remainder = bytes.count % blockSize if remainder == 0 { return bytes } let paddingCount = blockSize - remainder if paddingCount > 0 { return bytes + Array(repeating: 0, count: paddingCount) } return bytes } // MARK: - GF /// The Field GF(2^128) private final class GF { static let r = UInt128(a: 0xE100000000000000, b: 0) let blockSize: Int let h: UInt128 // AAD won't change let aadLength: Int // Updated for every consumed block var ciphertextLength: Int // Start with 0 var x: UInt128 init(aad: [UInt8], h: UInt128, blockSize: Int) { self.blockSize = blockSize self.aadLength = aad.count self.ciphertextLength = 0 self.h = h self.x = 0 // Calculate for AAD at the beginning self.x = GF.calculateX(aad: aad, x: self.x, h: h, blockSize: blockSize) } @discardableResult func ghashUpdate(block ciphertextBlock: Array) -> UInt128 { self.ciphertextLength += ciphertextBlock.count self.x = GF.calculateX(block: addPadding(ciphertextBlock, blockSize: self.blockSize), x: self.x, h: self.h, blockSize: self.blockSize) return self.x } func ghashFinish() -> UInt128 { // len(A) || len(C) let len = UInt128(a: UInt64(aadLength * 8), b: UInt64(ciphertextLength * 8)) x = GF.multiply(self.x ^ len, self.h) return self.x } // GHASH. One-time calculation static func ghash(x startx: UInt128 = 0, h: UInt128, aad: Array, ciphertext: Array, blockSize: Int) -> UInt128 { var x = self.calculateX(aad: aad, x: startx, h: h, blockSize: blockSize) x = self.calculateX(ciphertext: ciphertext, x: x, h: h, blockSize: blockSize) // len(aad) || len(ciphertext) let len = UInt128(a: UInt64(aad.count * 8), b: UInt64(ciphertext.count * 8)) x = self.multiply(x ^ len, h) return x } // Calculate Ciphertext part, for all blocks // Not used with incremental calculation. private static func calculateX(ciphertext: [UInt8], x startx: UInt128, h: UInt128, blockSize: Int) -> UInt128 { let pciphertext = addPadding(ciphertext, blockSize: blockSize) let blocksCount = pciphertext.count / blockSize var x = startx for i in 0.., x: UInt128, h: UInt128, blockSize: Int) -> UInt128 { let k = x ^ UInt128(ciphertextBlock) return self.multiply(k, h) } // Calculate AAD part, for all blocks private static func calculateX(aad: [UInt8], x startx: UInt128, h: UInt128, blockSize: Int) -> UInt128 { let paad = addPadding(aad, blockSize: blockSize) let blocksCount = paad.count / blockSize var x = startx for i in 0.. UInt128 { var z: UInt128 = 0 var v = x var k = UInt128(a: 1 << 63, b: 0) for _ in 0..<128 { if y & k == k { z = z ^ v } if v & 1 != 1 { v = v >> 1 } else { v = (v >> 1) ^ self.r } k = k >> 1 } return z } } ================================================ FILE: Sources/CryptoSwift/BlockMode/OCB.swift ================================================ // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // The OCB Authenticated-Encryption Algorithm // https://tools.ietf.org/html/rfc7253 // public final class OCB: BlockMode { public enum Mode { /// In combined mode, the authentication tag is directly appended to the encrypted message. This is usually what you want. case combined /// Some applications may need to store the authentication tag and the encrypted message at different locations. case detached } public let options: BlockModeOption = [.initializationVectorRequired] public enum Error: Swift.Error { case invalidNonce case fail } private let N: Array private let additionalAuthenticatedData: Array? private let mode: Mode public let customBlockSize: Int? = nil /// Length of authentication tag, in bytes. /// For encryption, the value is given as init parameter. /// For decryption, the length of given authentication tag is used. private let tagLength: Int // `authenticationTag` nil for encryption, known tag for decryption /// For encryption, the value is set at the end of the encryption. /// For decryption, this is a known Tag to validate against. public var authenticationTag: Array? // encrypt public init(nonce N: Array, additionalAuthenticatedData: Array? = nil, tagLength: Int = 16, mode: Mode = .detached) { self.N = N self.additionalAuthenticatedData = additionalAuthenticatedData self.mode = mode self.tagLength = tagLength } // decrypt @inlinable public convenience init(nonce N: Array, authenticationTag: Array, additionalAuthenticatedData: Array? = nil, mode: Mode = .detached) { self.init(nonce: N, additionalAuthenticatedData: additionalAuthenticatedData, tagLength: authenticationTag.count, mode: mode) self.authenticationTag = authenticationTag } public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { if self.N.isEmpty || self.N.count > 15 { throw Error.invalidNonce } let worker = OCBModeWorker(N: N.slice, aad: self.additionalAuthenticatedData?.slice, expectedTag: self.authenticationTag, tagLength: self.tagLength, mode: self.mode, cipherOperation: cipherOperation, encryptionOperation: encryptionOperation) worker.didCalculateTag = { [weak self] tag in self?.authenticationTag = tag } return worker } } // MARK: - Worker final class OCBModeWorker: BlockModeWorker, FinalizingEncryptModeWorker, FinalizingDecryptModeWorker { let cipherOperation: CipherOperationOnBlock var hashOperation: CipherOperationOnBlock! // Callback called when authenticationTag is ready var didCalculateTag: ((Array) -> Void)? private let tagLength: Int let blockSize = 16 // 128 bit var additionalBufferSize: Int private let mode: OCB.Mode // Additional authenticated data private let aad: ArraySlice? // Known Tag used to validate during decryption private var expectedTag: Array? /* * KEY-DEPENDENT */ // NOTE: elements are lazily calculated private var l = [Array]() private var lAsterisk: Array private var lDollar: Array /* * PER-ENCRYPTION/DECRYPTION */ private var mainBlockCount: UInt64 private var offsetMain: Array private var checksum: Array init(N: ArraySlice, aad: ArraySlice? = nil, expectedTag: Array? = nil, tagLength: Int, mode: OCB.Mode, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) { self.cipherOperation = cipherOperation self.hashOperation = encryptionOperation self.mode = mode self.aad = aad self.expectedTag = expectedTag self.tagLength = tagLength if mode == .combined { self.additionalBufferSize = tagLength } else { self.additionalBufferSize = 0 } /* * KEY-DEPENDENT INITIALIZATION */ let zeros = Array(repeating: 0, count: self.blockSize) self.lAsterisk = self.hashOperation(zeros.slice)! /// L_* = ENCIPHER(K, zeros(128)) self.lDollar = double(self.lAsterisk) /// L_$ = double(L_*) self.l.append(double(self.lDollar)) /// L_0 = double(L_$) /* * NONCE-DEPENDENT AND PER-ENCRYPTION/DECRYPTION INITIALIZATION */ /// Nonce = num2str(TAGLEN mod 128,7) || zeros(120-bitlen(N)) || 1 || N var nonce = Array(repeating: 0, count: blockSize) nonce[(nonce.count - N.count)...] = N nonce[0] = UInt8(tagLength) << 4 nonce[blockSize - 1 - N.count] |= 1 /// bottom = str2num(Nonce[123..128]) let bottom = nonce[15] & 0x3F /// Ktop = ENCIPHER(K, Nonce[1..122] || zeros(6)) nonce[15] &= 0xC0 let Ktop = self.hashOperation(nonce.slice)! /// Stretch = Ktop || (Ktop[1..64] xor Ktop[9..72]) let Stretch = Ktop + xor(Ktop[0..<8], Ktop[1..<9]) /// Offset_0 = Stretch[1+bottom..128+bottom] var offsetMAIN_0 = Array(repeating: 0, count: blockSize) let bits = bottom % 8 let bytes = Int(bottom / 8) if bits == 0 { offsetMAIN_0[0..> (8 - bits))) } } self.mainBlockCount = 0 self.offsetMain = Array(offsetMAIN_0.slice) self.checksum = Array(repeating: 0, count: self.blockSize) /// Checksum_0 = zeros(128) } /// L_i = double(L_{i-1}) for every integer i > 0 func getLSub(_ n: Int) -> Array { while n >= self.l.count { self.l.append(double(self.l.last!)) } return self.l[n] } func computeTag() -> Array { let sum = self.hashAAD() /// Tag = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) xor HASH(K,A) return xor(self.hashOperation(xor(xor(self.checksum, self.offsetMain).slice, self.lDollar))!, sum) } func hashAAD() -> Array { var sum = Array(repeating: 0, count: blockSize) guard let aad = self.aad else { return sum } var offset = Array(repeating: 0, count: blockSize) var blockCount: UInt64 = 1 for aadBlock in aad.batched(by: self.blockSize) { if aadBlock.count == self.blockSize { /// Offset_i = Offset_{i-1} xor L_{ntz(i)} offset = xor(offset, self.getLSub(ntz(blockCount))) /// Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) sum = xor(sum, self.hashOperation(xor(aadBlock, offset))!) } else { if !aadBlock.isEmpty { /// Offset_* = Offset_m xor L_* offset = xor(offset, self.lAsterisk) /// CipherInput = (A_* || 1 || zeros(127-bitlen(A_*))) xor Offset_* let cipherInput: Array = xor(extend(aadBlock, size: blockSize), offset) /// Sum = Sum_m xor ENCIPHER(K, CipherInput) sum = xor(sum, self.hashOperation(cipherInput.slice)!) } } blockCount += 1 } return sum } func encrypt(block plaintext: ArraySlice) -> Array { if plaintext.count == self.blockSize { return self.processBlock(block: plaintext, forEncryption: true) } else { return self.processFinalBlock(block: plaintext, forEncryption: true) } } func finalize(encrypt ciphertext: ArraySlice) throws -> ArraySlice { let tag = self.computeTag() self.didCalculateTag?(tag) switch self.mode { case .combined: return ciphertext + tag case .detached: return ciphertext } } func decrypt(block ciphertext: ArraySlice) -> Array { if ciphertext.count == self.blockSize { return self.processBlock(block: ciphertext, forEncryption: false) } else { return self.processFinalBlock(block: ciphertext, forEncryption: false) } } func finalize(decrypt plaintext: ArraySlice) throws -> ArraySlice { // do nothing plaintext } private func processBlock(block: ArraySlice, forEncryption: Bool) -> Array { /* * OCB-ENCRYPT/OCB-DECRYPT: Process any whole blocks */ self.mainBlockCount += 1 /// Offset_i = Offset_{i-1} xor L_{ntz(i)} self.offsetMain = xor(self.offsetMain, self.getLSub(ntz(self.mainBlockCount))) /// C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i) /// P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i) var mainBlock = Array(block) mainBlock = xor(mainBlock, offsetMain) mainBlock = self.cipherOperation(mainBlock.slice)! mainBlock = xor(mainBlock, self.offsetMain) /// Checksum_i = Checksum_{i-1} xor P_i if forEncryption { self.checksum = xor(self.checksum, block) } else { self.checksum = xor(self.checksum, mainBlock) } return mainBlock } private func processFinalBlock(block: ArraySlice, forEncryption: Bool) -> Array { let out: Array if block.isEmpty { /// C_* = /// P_* = out = [] } else { /// Offset_* = Offset_m xor L_* self.offsetMain = xor(self.offsetMain, self.lAsterisk) /// Pad = ENCIPHER(K, Offset_*) let Pad = self.hashOperation(self.offsetMain.slice)! /// C_* = P_* xor Pad[1..bitlen(P_*)] /// P_* = C_* xor Pad[1..bitlen(C_*)] out = xor(block, Pad[0..) throws -> ArraySlice { // Validate tag switch self.mode { case .combined: // overwrite expectedTag property used later for verification self.expectedTag = Array(ciphertext.suffix(self.tagLength)) return ciphertext[ciphertext.startIndex..) throws -> ArraySlice { // Calculate MAC tag. let computedTag = self.computeTag() // Validate tag guard let expectedTag = self.expectedTag, computedTag == expectedTag else { throw OCB.Error.fail } return plaintext } } // MARK: - Local utils private func ntz(_ x: UInt64) -> Int { if x == 0 { return 64 } var xv = x var n = 0 while (xv & 1) == 0 { n += 1 xv = xv >> 1 } return n } private func double(_ block: Array) -> Array { var ( carry, result) = shiftLeft(block) /* * NOTE: This construction is an attempt at a constant-time implementation. */ result[15] ^= (0x87 >> ((1 - carry) << 3)) return result } private func shiftLeft(_ block: Array) -> (UInt8, Array) { var output = Array(repeating: 0, count: block.count) var bit: UInt8 = 0 for i in 0..> 7) & 1 } return (bit, output) } private func extend(_ block: ArraySlice, size: Int) -> Array { var output = Array(repeating: 0, count: size) output[0.. // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // Output Feedback (OFB) // public struct OFB: BlockMode { public enum Error: Swift.Error { /// Invalid IV case invalidInitializationVector } public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt] private let iv: Array public let customBlockSize: Int? = nil public init(iv: Array) { self.iv = iv } public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { if self.iv.count != blockSize { throw Error.invalidInitializationVector } return OFBModeWorker(blockSize: blockSize, iv: self.iv.slice, cipherOperation: cipherOperation) } } struct OFBModeWorker: BlockModeWorker { let cipherOperation: CipherOperationOnBlock let blockSize: Int let additionalBufferSize: Int = 0 private let iv: ArraySlice private var prev: ArraySlice? init(blockSize: Int, iv: ArraySlice, cipherOperation: @escaping CipherOperationOnBlock) { self.blockSize = blockSize self.iv = iv self.cipherOperation = cipherOperation } @inlinable mutating func encrypt(block plaintext: ArraySlice) -> Array { guard let ciphertext = cipherOperation(prev ?? iv) else { return Array(plaintext) } self.prev = ciphertext.slice return xor(plaintext, ciphertext) } @inlinable mutating func decrypt(block ciphertext: ArraySlice) -> Array { guard let decrypted = cipherOperation(prev ?? iv) else { return Array(ciphertext) } let plaintext: Array = xor(decrypted, ciphertext) prev = decrypted.slice return plaintext } } ================================================ FILE: Sources/CryptoSwift/BlockMode/PCBC.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // Propagating Cipher Block Chaining (PCBC) // public struct PCBC: BlockMode { public enum Error: Swift.Error { /// Invalid IV case invalidInitializationVector } public let options: BlockModeOption = [.initializationVectorRequired, .paddingRequired] private let iv: Array public let customBlockSize: Int? = nil public init(iv: Array) { self.iv = iv } public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { if self.iv.count != blockSize { throw Error.invalidInitializationVector } return PCBCModeWorker(blockSize: blockSize, iv: self.iv.slice, cipherOperation: cipherOperation) } } struct PCBCModeWorker: BlockModeWorker { let cipherOperation: CipherOperationOnBlock var blockSize: Int let additionalBufferSize: Int = 0 private let iv: ArraySlice private var prev: ArraySlice? @inlinable init(blockSize: Int, iv: ArraySlice, cipherOperation: @escaping CipherOperationOnBlock) { self.blockSize = blockSize self.iv = iv self.cipherOperation = cipherOperation } @inlinable mutating func encrypt(block plaintext: ArraySlice) -> Array { guard let ciphertext = cipherOperation(xor(prev ?? iv, plaintext)) else { return Array(plaintext) } self.prev = xor(plaintext, ciphertext.slice) return ciphertext } @inlinable mutating func decrypt(block ciphertext: ArraySlice) -> Array { guard let plaintext = cipherOperation(ciphertext) else { return Array(ciphertext) } let result: Array = xor(prev ?? self.iv, plaintext) self.prev = xor(result, ciphertext) return result } } ================================================ FILE: Sources/CryptoSwift/Blowfish.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // https://en.wikipedia.org/wiki/Blowfish_(cipher) // Based on Paul Kocher implementation // public final class Blowfish { public enum Error: Swift.Error { /// Data padding is required case dataPaddingRequired /// Invalid key or IV case invalidKeyOrInitializationVector /// Invalid IV case invalidInitializationVector /// Invalid block mode case invalidBlockMode } public static let blockSize: Int = 8 // 64 bit public let keySize: Int private let blockMode: BlockMode private let padding: Padding private var decryptWorker: CipherModeWorker! private var encryptWorker: CipherModeWorker! private let N = 16 // rounds private var P: Array private var S: Array> private let origP: Array = [ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b ] private let origS: Array> = [ [ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a ], [ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 ], [ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 ], [ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 ] ] public init(key: Array, blockMode: BlockMode = CBC(iv: Array(repeating: 0, count: Blowfish.blockSize)), padding: Padding) throws { precondition(key.count >= 5 && key.count <= 56) self.blockMode = blockMode self.padding = padding self.keySize = key.count self.S = self.origS self.P = self.origP self.expandKey(key: key) try self.setupBlockModeWorkers() } private func setupBlockModeWorkers() throws { let decryptBlock = { [weak self] (block: ArraySlice) -> Array? in self?.decrypt(block: block) } let encryptBlock = { [weak self] (block: ArraySlice) -> Array? in self?.encrypt(block: block) } self.encryptWorker = try self.blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: encryptBlock, encryptionOperation: encryptBlock) if self.blockMode.options.contains(.useEncryptToDecrypt) { self.decryptWorker = try self.blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: encryptBlock, encryptionOperation: encryptBlock) } else { self.decryptWorker = try self.blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: decryptBlock, encryptionOperation: encryptBlock) } } private func reset() { self.S = self.origS self.P = self.origP // todo expand key } private func expandKey(key: Array) { var j = 0 for i in 0..<(self.N + 2) { var data: UInt32 = 0x0 for _ in 0..<4 { data = (data << 8) | UInt32(key[j]) j += 1 if j >= key.count { j = 0 } } self.P[i] ^= data } var datal: UInt32 = 0 var datar: UInt32 = 0 for i in stride(from: 0, to: self.N + 2, by: 2) { self.encryptBlowfishBlock(l: &datal, r: &datar) self.P[i] = datal self.P[i + 1] = datar } for i in 0..<4 { for j in stride(from: 0, to: 256, by: 2) { self.encryptBlowfishBlock(l: &datal, r: &datar) self.S[i][j] = datal self.S[i][j + 1] = datar } } } private func encrypt(block: ArraySlice) -> Array? { var result = Array() var l = UInt32(bytes: block[block.startIndex..> 24) & 0xff), UInt8((l >> 16) & 0xff) ] result += [ UInt8((l >> 8) & 0xff), UInt8((l >> 0) & 0xff) ] result += [ UInt8((r >> 24) & 0xff), UInt8((r >> 16) & 0xff) ] result += [ UInt8((r >> 8) & 0xff), UInt8((r >> 0) & 0xff) ] return result } private func decrypt(block: ArraySlice) -> Array? { var result = Array() var l = UInt32(bytes: block[block.startIndex..> 24) & 0xff), UInt8((l >> 16) & 0xff) ] result += [ UInt8((l >> 8) & 0xff), UInt8((l >> 0) & 0xff) ] result += [ UInt8((r >> 24) & 0xff), UInt8((r >> 16) & 0xff) ] result += [ UInt8((r >> 8) & 0xff), UInt8((r >> 0) & 0xff) ] return result } /// Encrypts the 8-byte padded buffer /// /// - Parameters: /// - l: left half /// - r: right half private func encryptBlowfishBlock(l: inout UInt32, r: inout UInt32) { var Xl = l var Xr = r for i in 0.. UInt32 { let f1 = self.S[0][Int(x >> 24) & 0xff] let f2 = self.S[1][Int(x >> 16) & 0xff] let f3 = self.S[2][Int(x >> 8) & 0xff] let f4 = self.S[3][Int(x & 0xff)] return ((f1 &+ f2) ^ f3) &+ f4 } } extension Blowfish: Cipher { /// Encrypt the 8-byte padded buffer, block by block. Note that for amounts of data larger than a block, it is not safe to just call encrypt() on successive blocks. /// /// - Parameter bytes: Plaintext data /// - Returns: Encrypted data public func encrypt(_ bytes: C) throws -> Array where C.Element == UInt8, C.Index == Int { let bytes = self.padding.add(to: Array(bytes), blockSize: Blowfish.blockSize) // FIXME: Array(bytes) copies var out = Array() out.reserveCapacity(bytes.count) for chunk in bytes.batched(by: Blowfish.blockSize) { out += self.encryptWorker.encrypt(block: chunk) } if self.blockMode.options.contains(.paddingRequired) && (out.count % Blowfish.blockSize != 0) { throw Error.dataPaddingRequired } return out } /// Decrypt the 8-byte padded buffer /// /// - Parameter bytes: Ciphertext data /// - Returns: Plaintext data public func decrypt(_ bytes: C) throws -> Array where C.Element == UInt8, C.Index == Int { if self.blockMode.options.contains(.paddingRequired) && (bytes.count % Blowfish.blockSize != 0) { throw Error.dataPaddingRequired } var out = Array() out.reserveCapacity(bytes.count) for chunk in Array(bytes).batched(by: Blowfish.blockSize) { out += self.decryptWorker.decrypt(block: chunk) // FIXME: copying here is ineffective } out = self.padding.remove(from: out, blockSize: Blowfish.blockSize) return out } } ================================================ FILE: Sources/CryptoSwift/CBCMAC.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public final class CBCMAC: CMAC { public override func authenticate(_ bytes: Array) throws -> Array { var inBytes = bytes bitPadding(to: &inBytes, blockSize: CMAC.BlockSize) let blocks = inBytes.batched(by: CMAC.BlockSize) var lastBlockEncryptionResult: [UInt8] = CBCMAC.Zero try blocks.forEach { block in let aes = try AES(key: Array(key), blockMode: CBC(iv: lastBlockEncryptionResult), padding: .noPadding) lastBlockEncryptionResult = try aes.encrypt(block) } return lastBlockEncryptionResult } } ================================================ FILE: Sources/CryptoSwift/CMAC.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public class CMAC: Authenticator { public enum Error: Swift.Error { case wrongKeyLength } internal let key: SecureBytes internal static let BlockSize: Int = 16 internal static let Zero: Array = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] private static let Rb: Array = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87] public init(key: Array) throws { self.key = SecureBytes(bytes: key) } // MARK: Authenticator // AES-CMAC public func authenticate(_ bytes: Array) throws -> Array { let cipher = try AES(key: Array(key), blockMode: CBC(iv: CMAC.Zero), padding: .noPadding) return try self.authenticate(bytes, cipher: cipher) } // CMAC using a Cipher public func authenticate(_ bytes: Array, cipher: Cipher) throws -> Array { let l = try cipher.encrypt(CMAC.Zero) var subKey1 = self.leftShiftOneBit(l) if (l[0] & 0x80) != 0 { subKey1 = xor(CMAC.Rb, subKey1) } var subKey2 = self.leftShiftOneBit(subKey1) if (subKey1[0] & 0x80) != 0 { subKey2 = xor(CMAC.Rb, subKey2) } let lastBlockComplete: Bool let blockCount = (bytes.count + CMAC.BlockSize - 1) / CMAC.BlockSize if blockCount == 0 { lastBlockComplete = false } else { lastBlockComplete = bytes.count % CMAC.BlockSize == 0 } var paddedBytes = bytes if !lastBlockComplete { bitPadding(to: &paddedBytes, blockSize: CMAC.BlockSize) } var blocks = Array(paddedBytes.batched(by: CMAC.BlockSize)) var lastBlock = blocks.popLast()! if lastBlockComplete { lastBlock = xor(lastBlock, subKey1) } else { lastBlock = xor(lastBlock, subKey2) } var x = Array(repeating: 0x00, count: CMAC.BlockSize) var y = Array(repeating: 0x00, count: CMAC.BlockSize) for block in blocks { y = xor(block, x) x = try cipher.encrypt(y) } // the difference between CMAC and CBC-MAC is that CMAC xors the final block with a secret value y = self.process(lastBlock: lastBlock, with: x) return try cipher.encrypt(y) } func process(lastBlock: ArraySlice, with x: [UInt8]) -> [UInt8] { xor(lastBlock, x) } // MARK: Helper methods /** Performs left shift by one bit to the bit string acquired after concatenating al bytes in the byte array - parameters: - bytes: byte array - returns: bit shifted bit string split again in array of bytes */ private func leftShiftOneBit(_ bytes: Array) -> Array { var shifted = Array(repeating: 0x00, count: bytes.count) let last = bytes.count - 1 for index in 0..= 0) var carry = word var i = shift while carry > 0 { let (d, c) = self[i].addingReportingOverflow(carry) self[i] = d carry = (c ? 1 : 0) i += 1 } } /// Add the digit `d` to this integer and return the result. /// `d` is shifted `shift` words to the left before being added. /// /// - Complexity: O(max(count, shift)) internal func addingWord(_ word: Word, shiftedBy shift: Int = 0) -> CS.BigUInt { var r = self r.addWord(word, shiftedBy: shift) return r } /// Add `b` to this integer in place. /// `b` is shifted `shift` words to the left before being added. /// /// - Complexity: O(max(count, b.count + shift)) internal mutating func add(_ b: CS.BigUInt, shiftedBy shift: Int = 0) { precondition(shift >= 0) var carry = false var bi = 0 let bc = b.count while bi < bc || carry { let ai = shift + bi let (d, c) = self[ai].addingReportingOverflow(b[bi]) if carry { let (d2, c2) = d.addingReportingOverflow(1) self[ai] = d2 carry = c || c2 } else { self[ai] = d carry = c } bi += 1 } } /// Add `b` to this integer and return the result. /// `b` is shifted `shift` words to the left before being added. /// /// - Complexity: O(max(count, b.count + shift)) internal func adding(_ b: CS.BigUInt, shiftedBy shift: Int = 0) -> CS.BigUInt { var r = self r.add(b, shiftedBy: shift) return r } /// Increment this integer by one. If `shift` is non-zero, it selects /// the word that is to be incremented. /// /// - Complexity: O(count + shift) internal mutating func increment(shiftedBy shift: Int = 0) { self.addWord(1, shiftedBy: shift) } /// Add `a` and `b` together and return the result. /// /// - Complexity: O(max(a.count, b.count)) public static func +(a: CS.BigUInt, b: CS.BigUInt) -> CS.BigUInt { return a.adding(b) } /// Add `a` and `b` together, and store the sum in `a`. /// /// - Complexity: O(max(a.count, b.count)) public static func +=(a: inout CS.BigUInt, b: CS.BigUInt) { a.add(b, shiftedBy: 0) } } extension CS.BigInt { /// Add `a` to `b` and return the result. public static func +(a: CS.BigInt, b: CS.BigInt) -> CS.BigInt { switch (a.sign, b.sign) { case (.plus, .plus): return CS.BigInt(sign: .plus, magnitude: a.magnitude + b.magnitude) case (.minus, .minus): return CS.BigInt(sign: .minus, magnitude: a.magnitude + b.magnitude) case (.plus, .minus): if a.magnitude >= b.magnitude { return CS.BigInt(sign: .plus, magnitude: a.magnitude - b.magnitude) } else { return CS.BigInt(sign: .minus, magnitude: b.magnitude - a.magnitude) } case (.minus, .plus): if b.magnitude >= a.magnitude { return CS.BigInt(sign: .plus, magnitude: b.magnitude - a.magnitude) } else { return CS.BigInt(sign: .minus, magnitude: a.magnitude - b.magnitude) } } } /// Add `b` to `a` in place. public static func +=(a: inout CS.BigInt, b: CS.BigInt) { a = a + b } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/BigInt.swift ================================================ // // CS.BigInt.swift // CS.BigInt // // Created by Károly Lőrentey on 2015-12-27. // Copyright © 2016-2017 Károly Lőrentey. // //MARK: CS.BigInt extension CS { /// An arbitrary precision signed integer type, also known as a "big integer". /// /// Operations on big integers never overflow, but they might take a long time to execute. /// The amount of memory (and address space) available is the only constraint to the magnitude of these numbers. /// /// This particular big integer type uses base-2^64 digits to represent integers. /// /// `BigInt` is essentially a tiny wrapper that extends `BigUInt` with a sign bit and provides signed integer /// operations. Both the underlying absolute value and the negative/positive flag are available as read-write /// properties. /// /// Not all algorithms of `BigUInt` are available for `BigInt` values; for example, there is no square root or /// primality test for signed integers. When you need to call one of these, just extract the absolute value: /// /// ```Swift /// CS.BigInt(255).abs.isPrime() // Returns false /// ``` /// public struct BigInt: SignedInteger { public enum Sign { case plus case minus } public typealias Magnitude = BigUInt /// The type representing a digit in `BigInt`'s underlying number system. public typealias Word = BigUInt.Word public static var isSigned: Bool { return true } /// The absolute value of this integer. public var magnitude: BigUInt /// True iff the value of this integer is negative. public var sign: Sign /// Initializes a new big integer with the provided absolute number and sign flag. public init(sign: Sign, magnitude: BigUInt) { self.sign = (magnitude.isZero ? .plus : sign) self.magnitude = magnitude } /// Return true iff this integer is zero. /// /// - Complexity: O(1) public var isZero: Bool { return magnitude.isZero } /// Returns `-1` if this value is negative and `1` if it’s positive; otherwise, `0`. /// /// - Returns: The sign of this number, expressed as an integer of the same type. public func signum() -> CS.BigInt { switch sign { case .plus: return isZero ? 0 : 1 case .minus: return -1 } } } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/BigUInt.swift ================================================ // // BigUInt.swift // BigInt // // Created by Károly Lőrentey on 2015-12-26. // Copyright © 2016-2017 Károly Lőrentey. // extension CS { /// An arbitrary precision unsigned integer type, also known as a "big integer". /// /// Operations on big integers never overflow, but they may take a long time to execute. /// The amount of memory (and address space) available is the only constraint to the magnitude of these numbers. /// /// This particular big integer type uses base-2^64 digits to represent integers; you can think of it as a wrapper /// around `Array`. (In fact, `BigUInt` only uses an array if there are more than two digits.) public struct BigUInt: UnsignedInteger { /// The type representing a digit in `BigUInt`'s underlying number system. public typealias Word = UInt /// The storage variants of a `BigUInt`. enum Kind { /// Value consists of the two specified words (low and high). Either or both words may be zero. case inline(Word, Word) /// Words are stored in a slice of the storage array. case slice(from: Int, to: Int) /// Words are stored in the storage array. case array } internal fileprivate(set) var kind: Kind // Internal for testing only internal fileprivate(set) var storage: [Word] // Internal for testing only; stored separately to prevent COW copies /// Initializes a new BigUInt with value 0. public init() { self.kind = .inline(0, 0) self.storage = [] } internal init(word: Word) { self.kind = .inline(word, 0) self.storage = [] } internal init(low: Word, high: Word) { self.kind = .inline(low, high) self.storage = [] } /// Initializes a new BigUInt with the specified digits. The digits are ordered from least to most significant. public init(words: [Word]) { self.kind = .array self.storage = words normalize() } internal init(words: [Word], from startIndex: Int, to endIndex: Int) { self.kind = .slice(from: startIndex, to: endIndex) self.storage = words normalize() } } } extension CS.BigUInt { public static var isSigned: Bool { return false } /// Return true iff this integer is zero. /// /// - Complexity: O(1) var isZero: Bool { switch kind { case .inline(0, 0): return true case .array: return storage.isEmpty default: return false } } /// Returns `1` if this value is, positive; otherwise, `0`. /// /// - Returns: The sign of this number, expressed as an integer of the same type. public func signum() -> CS.BigUInt { return isZero ? 0 : 1 } } extension CS.BigUInt { mutating func ensureArray() { switch kind { case let .inline(w0, w1): kind = .array storage = w1 != 0 ? [w0, w1] : w0 != 0 ? [w0] : [] case let .slice(from: start, to: end): kind = .array storage = Array(storage[start ..< end]) case .array: break } } var capacity: Int { guard case .array = kind else { return 0 } return storage.capacity } mutating func reserveCapacity(_ minimumCapacity: Int) { switch kind { case let .inline(w0, w1): kind = .array storage.reserveCapacity(minimumCapacity) if w1 != 0 { storage.append(w0) storage.append(w1) } else if w0 != 0 { storage.append(w0) } case let .slice(from: start, to: end): kind = .array var words: [Word] = [] words.reserveCapacity(Swift.max(end - start, minimumCapacity)) words.append(contentsOf: storage[start ..< end]) storage = words case .array: storage.reserveCapacity(minimumCapacity) } } /// Gets rid of leading zero digits in the digit array and converts slices into inline digits when possible. internal mutating func normalize() { switch kind { case .slice(from: let start, to: var end): assert(start >= 0 && end <= storage.count && start <= end) while start < end, storage[end - 1] == 0 { end -= 1 } switch end - start { case 0: kind = .inline(0, 0) storage = [] case 1: kind = .inline(storage[start], 0) storage = [] case 2: kind = .inline(storage[start], storage[start + 1]) storage = [] case storage.count: assert(start == 0) kind = .array default: kind = .slice(from: start, to: end) } case .array where storage.last == 0: while storage.last == 0 { storage.removeLast() } default: break } } /// Set this integer to 0 without releasing allocated storage capacity (if any). mutating func clear() { self.load(0) } /// Set this integer to `value` by copying its digits without releasing allocated storage capacity (if any). mutating func load(_ value: CS.BigUInt) { switch kind { case .inline, .slice: self = value case .array: self.storage.removeAll(keepingCapacity: true) self.storage.append(contentsOf: value.words) } } } extension CS.BigUInt { //MARK: Collection-like members /// The number of digits in this integer, excluding leading zero digits. var count: Int { switch kind { case let .inline(w0, w1): return w1 != 0 ? 2 : w0 != 0 ? 1 : 0 case let .slice(from: start, to: end): return end - start case .array: return storage.count } } /// Get or set a digit at a given index. /// /// - Note: Unlike a normal collection, it is OK for the index to be greater than or equal to `endIndex`. /// The subscripting getter returns zero for indexes beyond the most significant digit. /// Setting these extended digits automatically appends new elements to the underlying digit array. /// - Requires: index >= 0 /// - Complexity: The getter is O(1). The setter is O(1) if the conditions below are true; otherwise it's O(count). /// - The integer's storage is not shared with another integer /// - The integer wasn't created as a slice of another integer /// - `index < count` subscript(_ index: Int) -> Word { get { precondition(index >= 0) switch (kind, index) { case (.inline(let w0, _), 0): return w0 case (.inline(_, let w1), 1): return w1 case (.slice(from: let start, to: let end), _) where index < end - start: return storage[start + index] case (.array, _) where index < storage.count: return storage[index] default: return 0 } } set(word) { precondition(index >= 0) switch (kind, index) { case let (.inline(_, w1), 0): kind = .inline(word, w1) case let (.inline(w0, _), 1): kind = .inline(w0, word) case let (.slice(from: start, to: end), _) where index < end - start: replace(at: index, with: word) case (.array, _) where index < storage.count: replace(at: index, with: word) default: extend(at: index, with: word) } } } private mutating func replace(at index: Int, with word: Word) { ensureArray() precondition(index < storage.count) storage[index] = word if word == 0, index == storage.count - 1 { normalize() } } private mutating func extend(at index: Int, with word: Word) { guard word != 0 else { return } reserveCapacity(index + 1) precondition(index >= storage.count) storage.append(contentsOf: repeatElement(0, count: index - storage.count)) storage.append(word) } /// Returns an integer built from the digits of this integer in the given range. internal func extract(_ bounds: Range) -> CS.BigUInt { switch kind { case let .inline(w0, w1): let bounds = bounds.clamped(to: 0 ..< 2) if bounds == 0 ..< 2 { return CS.BigUInt(low: w0, high: w1) } else if bounds == 0 ..< 1 { return CS.BigUInt(word: w0) } else if bounds == 1 ..< 2 { return CS.BigUInt(word: w1) } else { return CS.BigUInt() } case let .slice(from: start, to: end): let s = Swift.min(end, start + Swift.max(bounds.lowerBound, 0)) let e = Swift.max(s, (bounds.upperBound > end - start ? end : start + bounds.upperBound)) return CS.BigUInt(words: storage, from: s, to: e) case .array: let b = bounds.clamped(to: storage.startIndex ..< storage.endIndex) return CS.BigUInt(words: storage, from: b.lowerBound, to: b.upperBound) } } internal func extract(_ bounds: Bounds) -> CS.BigUInt where Bounds.Bound == Int { return self.extract(bounds.relative(to: 0 ..< Int.max)) } } extension CS.BigUInt { internal mutating func shiftRight(byWords amount: Int) { assert(amount >= 0) guard amount > 0 else { return } switch kind { case let .inline(_, w1) where amount == 1: kind = .inline(w1, 0) case .inline(_, _): kind = .inline(0, 0) case let .slice(from: start, to: end): let s = start + amount if s >= end { kind = .inline(0, 0) } else { kind = .slice(from: s, to: end) normalize() } case .array: if amount >= storage.count { storage.removeAll(keepingCapacity: true) } else { storage.removeFirst(amount) } } } internal mutating func shiftLeft(byWords amount: Int) { assert(amount >= 0) guard amount > 0 else { return } guard !isZero else { return } switch kind { case let .inline(w0, 0) where amount == 1: kind = .inline(0, w0) case let .inline(w0, w1): let c = (w1 == 0 ? 1 : 2) storage.reserveCapacity(amount + c) storage.append(contentsOf: repeatElement(0, count: amount)) storage.append(w0) if w1 != 0 { storage.append(w1) } kind = .array case let .slice(from: start, to: end): var words: [Word] = [] words.reserveCapacity(amount + count) words.append(contentsOf: repeatElement(0, count: amount)) words.append(contentsOf: storage[start ..< end]) storage = words kind = .array case .array: storage.insert(contentsOf: repeatElement(0, count: amount), at: 0) } } } extension CS.BigUInt { //MARK: Low and High /// Split this integer into a high-order and a low-order part. /// /// - Requires: count > 1 /// - Returns: `(low, high)` such that /// - `self == low.add(high, shiftedBy: middleIndex)` /// - `high.width <= floor(width / 2)` /// - `low.width <= ceil(width / 2)` /// - Complexity: Typically O(1), but O(count) in the worst case, because high-order zero digits need to be removed after the split. internal var split: (high: CS.BigUInt, low: CS.BigUInt) { precondition(count > 1) let mid = middleIndex return (self.extract(mid...), self.extract(.. 1 internal var low: CS.BigUInt { return self.extract(0 ..< middleIndex) } /// The high-order half of this CS.BigUInt. /// /// - Returns: `self[middleIndex ..< count]` /// - Requires: count > 1 internal var high: CS.BigUInt { return self.extract(middleIndex ..< count) } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/BitwiseOps.swift ================================================ // // BitwiseOps.swift // CS.BigInt // // Created by Károly Lőrentey on 2016-01-03. // Copyright © 2016-2017 Károly Lőrentey. // //MARK: Bitwise Operations extension CS.BigUInt { /// Return the ones' complement of `a`. /// /// - Complexity: O(a.count) public static prefix func ~(a: CS.BigUInt) -> CS.BigUInt { return CS.BigUInt(words: a.words.map { ~$0 }) } /// Calculate the bitwise OR of `a` and `b`, and store the result in `a`. /// /// - Complexity: O(max(a.count, b.count)) public static func |= (a: inout CS.BigUInt, b: CS.BigUInt) { a.reserveCapacity(b.count) for i in 0 ..< b.count { a[i] |= b[i] } } /// Calculate the bitwise AND of `a` and `b` and return the result. /// /// - Complexity: O(max(a.count, b.count)) public static func &= (a: inout CS.BigUInt, b: CS.BigUInt) { for i in 0 ..< Swift.max(a.count, b.count) { a[i] &= b[i] } } /// Calculate the bitwise XOR of `a` and `b` and return the result. /// /// - Complexity: O(max(a.count, b.count)) public static func ^= (a: inout CS.BigUInt, b: CS.BigUInt) { a.reserveCapacity(b.count) for i in 0 ..< b.count { a[i] ^= b[i] } } } extension CS.BigInt { public static prefix func ~(x: CS.BigInt) -> CS.BigInt { switch x.sign { case .plus: return CS.BigInt(sign: .minus, magnitude: x.magnitude + 1) case .minus: return CS.BigInt(sign: .plus, magnitude: x.magnitude - 1) } } public static func &(lhs: inout CS.BigInt, rhs: CS.BigInt) -> CS.BigInt { let left = lhs.words let right = rhs.words // Note we aren't using left.count/right.count here; we account for the sign bit separately later. let count = Swift.max(lhs.magnitude.count, rhs.magnitude.count) var words: [UInt] = [] words.reserveCapacity(count) for i in 0 ..< count { words.append(left[i] & right[i]) } if lhs.sign == .minus && rhs.sign == .minus { words.twosComplement() return CS.BigInt(sign: .minus, magnitude: CS.BigUInt(words: words)) } return CS.BigInt(sign: .plus, magnitude: CS.BigUInt(words: words)) } public static func |(lhs: inout CS.BigInt, rhs: CS.BigInt) -> CS.BigInt { let left = lhs.words let right = rhs.words // Note we aren't using left.count/right.count here; we account for the sign bit separately later. let count = Swift.max(lhs.magnitude.count, rhs.magnitude.count) var words: [UInt] = [] words.reserveCapacity(count) for i in 0 ..< count { words.append(left[i] | right[i]) } if lhs.sign == .minus || rhs.sign == .minus { words.twosComplement() return CS.BigInt(sign: .minus, magnitude: CS.BigUInt(words: words)) } return CS.BigInt(sign: .plus, magnitude: CS.BigUInt(words: words)) } public static func ^(lhs: inout CS.BigInt, rhs: CS.BigInt) -> CS.BigInt { let left = lhs.words let right = rhs.words // Note we aren't using left.count/right.count here; we account for the sign bit separately later. let count = Swift.max(lhs.magnitude.count, rhs.magnitude.count) var words: [UInt] = [] words.reserveCapacity(count) for i in 0 ..< count { words.append(left[i] ^ right[i]) } if (lhs.sign == .minus) != (rhs.sign == .minus) { words.twosComplement() return CS.BigInt(sign: .minus, magnitude: CS.BigUInt(words: words)) } return CS.BigInt(sign: .plus, magnitude: CS.BigUInt(words: words)) } public static func &=(lhs: inout CS.BigInt, rhs: CS.BigInt) { lhs = lhs & rhs } public static func |=(lhs: inout CS.BigInt, rhs: CS.BigInt) { lhs = lhs | rhs } public static func ^=(lhs: inout CS.BigInt, rhs: CS.BigInt) { lhs = lhs ^ rhs } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/CS.swift ================================================ // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // To avoid name conflict with BigInt library, I choose to rename // BigInt -> BigInteger // BigUInt -> BigUInteger public typealias BigInteger = CS.BigInt public typealias BigUInteger = CS.BigUInt public enum CS { // namespace } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/Codable.swift ================================================ // // Codable.swift // CS.BigInt // // Created by Károly Lőrentey on 2017-8-11. // Copyright © 2016-2017 Károly Lőrentey. // extension CS { // Little-endian to big-endian struct Units: RandomAccessCollection where Words.Element: FixedWidthInteger, Words.Index == Int { typealias Word = Words.Element let words: Words init(of type: Unit.Type, _ words: Words) { precondition(Word.bitWidth % Unit.bitWidth == 0 || Unit.bitWidth % Word.bitWidth == 0) self.words = words } var count: Int { return (words.count * Word.bitWidth + Unit.bitWidth - 1) / Unit.bitWidth } var startIndex: Int { return 0 } var endIndex: Int { return count } subscript(_ index: Int) -> Unit { let index = count - 1 - index if Unit.bitWidth == Word.bitWidth { return Unit(words[index]) } else if Unit.bitWidth > Word.bitWidth { let c = Unit.bitWidth / Word.bitWidth var unit: Unit = 0 var j = 0 for i in (c * index) ..< Swift.min(c * (index + 1), words.endIndex) { unit |= Unit(words[i]) << j j += Word.bitWidth } return unit } // Unit.bitWidth < Word.bitWidth let c = Word.bitWidth / Unit.bitWidth let i = index / c let j = index % c return Unit(truncatingIfNeeded: words[i] >> (j * Unit.bitWidth)) } } } extension Array where Element: FixedWidthInteger { // Big-endian to little-endian init(count: Int?, generator: () throws -> Unit?) rethrows { typealias Word = Element precondition(Word.bitWidth % Unit.bitWidth == 0 || Unit.bitWidth % Word.bitWidth == 0) self = [] if Unit.bitWidth == Word.bitWidth { if let count = count { self.reserveCapacity(count) } while let unit = try generator() { self.append(Word(unit)) } } else if Unit.bitWidth > Word.bitWidth { let wordsPerUnit = Unit.bitWidth / Word.bitWidth if let count = count { self.reserveCapacity(count * wordsPerUnit) } while let unit = try generator() { var shift = Unit.bitWidth - Word.bitWidth while shift >= 0 { self.append(Word(truncatingIfNeeded: unit >> shift)) shift -= Word.bitWidth } } } else { let unitsPerWord = Word.bitWidth / Unit.bitWidth if let count = count { self.reserveCapacity((count + unitsPerWord - 1) / unitsPerWord) } var word: Word = 0 var c = 0 while let unit = try generator() { word <<= Unit.bitWidth word |= Word(unit) c += Unit.bitWidth if c == Word.bitWidth { self.append(word) word = 0 c = 0 } } if c > 0 { self.append(word << c) var shifted: Word = 0 for i in self.indices { let word = self[i] self[i] = shifted | (word >> c) shifted = word << (Word.bitWidth - c) } } } self.reverse() } } extension CS.BigInt: Codable { public init(from decoder: Decoder) throws { var container = try decoder.unkeyedContainer() // Decode sign let sign: CS.BigInt.Sign switch try container.decode(String.self) { case "+": sign = .plus case "-": sign = .minus default: throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, debugDescription: "Invalid big integer sign")) } // Decode magnitude let words = try [UInt](count: container.count?.advanced(by: -1)) { () -> UInt64? in guard !container.isAtEnd else { return nil } return try container.decode(UInt64.self) } let magnitude = CS.BigUInt(words: words) self.init(sign: sign, magnitude: magnitude) } public func encode(to encoder: Encoder) throws { var container = encoder.unkeyedContainer() try container.encode(sign == .plus ? "+" : "-") let units = CS.Units(of: UInt64.self, self.magnitude.words) if units.isEmpty { try container.encode(0 as UInt64) } else { try container.encode(contentsOf: units) } } } extension CS.BigUInt: Codable { public init(from decoder: Decoder) throws { let value = try CS.BigInt(from: decoder) guard value.sign == .plus else { throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "BigUInt cannot hold a negative value")) } self = value.magnitude } public func encode(to encoder: Encoder) throws { try CS.BigInt(sign: .plus, magnitude: self).encode(to: encoder) } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/Comparable.swift ================================================ // // Comparable.swift // CS.BigInt // // Created by Károly Lőrentey on 2016-01-03. // Copyright © 2016-2017 Károly Lőrentey. // import Foundation extension CS.BigUInt: Comparable { //MARK: Comparison /// Compare `a` to `b` and return an `NSComparisonResult` indicating their order. /// /// - Complexity: O(count) public static func compare(_ a: CS.BigUInt, _ b: CS.BigUInt) -> ComparisonResult { if a.count != b.count { return a.count > b.count ? .orderedDescending : .orderedAscending } for i in (0 ..< a.count).reversed() { let ad = a[i] let bd = b[i] if ad != bd { return ad > bd ? .orderedDescending : .orderedAscending } } return .orderedSame } /// Return true iff `a` is equal to `b`. /// /// - Complexity: O(count) public static func ==(a: CS.BigUInt, b: CS.BigUInt) -> Bool { return CS.BigUInt.compare(a, b) == .orderedSame } /// Return true iff `a` is less than `b`. /// /// - Complexity: O(count) public static func <(a: CS.BigUInt, b: CS.BigUInt) -> Bool { return CS.BigUInt.compare(a, b) == .orderedAscending } } extension CS.BigInt { /// Return true iff `a` is equal to `b`. public static func ==(a: CS.BigInt, b: CS.BigInt) -> Bool { return a.sign == b.sign && a.magnitude == b.magnitude } /// Return true iff `a` is less than `b`. public static func <(a: CS.BigInt, b: CS.BigInt) -> Bool { switch (a.sign, b.sign) { case (.plus, .plus): return a.magnitude < b.magnitude case (.plus, .minus): return false case (.minus, .plus): return true case (.minus, .minus): return a.magnitude > b.magnitude } } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/DataConversion.swift ================================================ // // DataConversion.swift // BigInt // // Created by Károly Lőrentey on 2016-01-04. // Copyright © 2016-2017 Károly Lőrentey. // import Foundation extension CS.BigUInt { //MARK: NSData Conversion /// Initialize a BigInt from bytes accessed from an UnsafeRawBufferPointer public init(_ buffer: UnsafeRawBufferPointer) { // This assumes Word is binary. precondition(Word.bitWidth % 8 == 0) self.init() let length = buffer.count guard length > 0 else { return } let bytesPerDigit = Word.bitWidth / 8 var index = length / bytesPerDigit var c = bytesPerDigit - length % bytesPerDigit if c == bytesPerDigit { c = 0 index -= 1 } var word: Word = 0 for byte in buffer { word <<= 8 word += Word(byte) c += 1 if c == bytesPerDigit { self[index] = word index -= 1 c = 0 word = 0 } } assert(c == 0 && word == 0 && index == -1) } /// Initializes an integer from the bits stored inside a piece of `Data`. /// The data is assumed to be in network (big-endian) byte order. public init(_ data: Data) { // This assumes Word is binary. precondition(Word.bitWidth % 8 == 0) self.init() let length = data.count guard length > 0 else { return } let bytesPerDigit = Word.bitWidth / 8 var index = length / bytesPerDigit var c = bytesPerDigit - length % bytesPerDigit if c == bytesPerDigit { c = 0 index -= 1 } let word: Word = data.withUnsafeBytes { buffPtr in var word: Word = 0 let p = buffPtr.bindMemory(to: UInt8.self) for byte in p { word <<= 8 word += Word(byte) c += 1 if c == bytesPerDigit { self[index] = word index -= 1 c = 0 word = 0 } } return word } assert(c == 0 && word == 0 && index == -1) } /// Return a `Data` value that contains the base-256 representation of this integer, in network (big-endian) byte order. public func serialize() -> Data { // This assumes Digit is binary. precondition(Word.bitWidth % 8 == 0) let byteCount = (self.bitWidth + 7) / 8 guard byteCount > 0 else { return Data() } var data = Data(count: byteCount) data.withUnsafeMutableBytes { buffPtr in let p = buffPtr.bindMemory(to: UInt8.self) var i = byteCount - 1 for var word in self.words { for _ in 0 ..< Word.bitWidth / 8 { p[i] = UInt8(word & 0xFF) word >>= 8 if i == 0 { assert(word == 0) break } i -= 1 } } } return data } } extension CS.BigInt { /// Initialize a BigInt from bytes accessed from an UnsafeRawBufferPointer, /// where the first byte indicates sign (0 for positive, 1 for negative) public init(_ buffer: UnsafeRawBufferPointer) { // This assumes Word is binary. precondition(Word.bitWidth % 8 == 0) self.init() let length = buffer.count // Serialized data for a BigInt should contain at least 2 bytes: one representing // the sign, and another for the non-zero magnitude. Zero is represented by an // empty Data struct, and negative zero is not supported. guard length > 1, let firstByte = buffer.first else { return } // The first byte gives the sign // This byte is compared to a bitmask to allow additional functionality to be added // to this byte in the future. self.sign = firstByte & 0b1 == 0 ? .plus : .minus self.magnitude = CS.BigUInt(UnsafeRawBufferPointer(rebasing: buffer.dropFirst(1))) } /// Initializes an integer from the bits stored inside a piece of `Data`. /// The data is assumed to be in network (big-endian) byte order with a first /// byte to represent the sign (0 for positive, 1 for negative) public init(_ data: Data) { // This assumes Word is binary. // This is the same assumption made when initializing CS.BigUInt from Data precondition(Word.bitWidth % 8 == 0) self.init() // Serialized data for a BigInt should contain at least 2 bytes: one representing // the sign, and another for the non-zero magnitude. Zero is represented by an // empty Data struct, and negative zero is not supported. guard data.count > 1, let firstByte = data.first else { return } // The first byte gives the sign // This byte is compared to a bitmask to allow additional functionality to be added // to this byte in the future. self.sign = firstByte & 0b1 == 0 ? .plus : .minus // The remaining bytes are read and stored as the magnitude self.magnitude = CS.BigUInt(data.dropFirst(1)) } /// Return a `Data` value that contains the base-256 representation of this integer, in network (big-endian) byte order and a prepended byte to indicate the sign (0 for positive, 1 for negative) public func serialize() -> Data { // Create a data object for the magnitude portion of the BigInt let magnitudeData = self.magnitude.serialize() // Similar to CS.BigUInt, a value of 0 should return an initialized, empty Data struct guard magnitudeData.count > 0 else { return magnitudeData } // Create a new Data struct for the signed BigInt value var data = Data(capacity: magnitudeData.count + 1) // The first byte should be 0 for a positive value, or 1 for a negative value // i.e., the sign bit is the LSB data.append(self.sign == .plus ? 0 : 1) data.append(magnitudeData) return data } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/Division.swift ================================================ // // Division.swift // CS.BigInt // // Created by Károly Lőrentey on 2016-01-03. // Copyright © 2016-2017 Károly Lőrentey. // //MARK: Full-width multiplication and division // TODO: Return to `where Magnitude == Self` when SR-13491 is resolved extension FixedWidthInteger { private var halfShift: Self { return Self(Self.bitWidth / 2) } private var high: Self { return self &>> halfShift } private var low: Self { let mask: Self = 1 &<< halfShift - 1 return self & mask } private var upshifted: Self { return self &<< halfShift } private var split: (high: Self, low: Self) { return (self.high, self.low) } private init(_ value: (high: Self, low: Self)) { self = value.high.upshifted + value.low } /// Divide the double-width integer `dividend` by `self` and return the quotient and remainder. /// /// - Requires: `dividend.high < self`, so that the result will fit in a single digit. /// - Complexity: O(1) with 2 divisions, 6 multiplications and ~12 or so additions/subtractions. internal func fastDividingFullWidth(_ dividend: (high: Self, low: Self.Magnitude)) -> (quotient: Self, remainder: Self) { // Division is complicated; doing it with single-digit operations is maddeningly complicated. // This is a Swift adaptation for "divlu2" in Hacker's Delight, // which is in turn a C adaptation of Knuth's Algorithm D (TAOCP vol 2, 4.3.1). precondition(dividend.high < self) // This replaces the implementation in stdlib, which is much slower. // FIXME: Speed up stdlib. It should use full-width idiv on Intel processors, and // fall back to a reasonably fast algorithm elsewhere. // The trick here is that we're actually implementing a 4/2 long division using half-words, // with the long division loop unrolled into two 3/2 half-word divisions. // Luckily, 3/2 half-word division can be approximated by a single full-word division operation // that, when the divisor is normalized, differs from the correct result by at most 2. /// Find the half-word quotient in `u / vn`, which must be normalized. /// `u` contains three half-words in the two halves of `u.high` and the lower half of /// `u.low`. (The weird distribution makes for a slightly better fit with the input.) /// `vn` contains the normalized divisor, consisting of two half-words. /// /// - Requires: u.high < vn && u.low.high == 0 && vn.leadingZeroBitCount == 0 func quotient(dividing u: (high: Self, low: Self), by vn: Self) -> Self { let (vn1, vn0) = vn.split // Get approximate quotient. let (q, r) = u.high.quotientAndRemainder(dividingBy: vn1) let p = q * vn0 // q is often already correct, but sometimes the approximation overshoots by at most 2. // The code that follows checks for this while being careful to only perform single-digit operations. if q.high == 0 && p <= r.upshifted + u.low { return q } let r2 = r + vn1 if r2.high != 0 { return q - 1 } if (q - 1).high == 0 && p - vn0 <= r2.upshifted + u.low { return q - 1 } //assert((r + 2 * vn1).high != 0 || p - 2 * vn0 <= (r + 2 * vn1).upshifted + u.low) return q - 2 } /// Divide 3 half-digits by 2 half-digits to get a half-digit quotient and a full-digit remainder. /// /// - Requires: u.high < v && u.low.high == 0 && vn.width = width(Digit) func quotientAndRemainder(dividing u: (high: Self, low: Self), by v: Self) -> (quotient: Self, remainder: Self) { let q = quotient(dividing: u, by: v) // Note that `uh.low` masks off a couple of bits, and `q * v` and the // subtraction are likely to overflow. Despite this, the end result (remainder) will // still be correct and it will fit inside a single (full) Digit. let r = Self(u) &- q &* v assert(r < v) return (q, r) } // Normalize the dividend and the divisor (self) such that the divisor has no leading zeroes. let z = Self(self.leadingZeroBitCount) let w = Self(Self.bitWidth) - z let vn = self << z let un32 = (z == 0 ? dividend.high : (dividend.high &<< z) | ((dividend.low as! Self) &>> w)) // No bits are lost let un10 = dividend.low &<< z let (un1, un0) = un10.split // Divide `(un32,un10)` by `vn`, splitting the full 4/2 division into two 3/2 ones. let (q1, un21) = quotientAndRemainder(dividing: (un32, (un1 as! Self)), by: vn) let (q0, rn) = quotientAndRemainder(dividing: (un21, (un0 as! Self)), by: vn) // Undo normalization of the remainder and combine the two halves of the quotient. let mod = rn >> z let div = Self((q1, q0)) return (div, mod) } /// Return the quotient of the 3/2-word division `x/y` as a single word. /// /// - Requires: (x.0, x.1) <= y && y.0.high != 0 /// - Returns: The exact value when it fits in a single word, otherwise `Self`. static func approximateQuotient(dividing x: (Self, Self, Self), by y: (Self, Self)) -> Self { // Start with q = (x.0, x.1) / y.0, (or Word.max on overflow) var q: Self var r: Self if x.0 == y.0 { q = Self.max let (s, o) = x.0.addingReportingOverflow(x.1) if o { return q } r = s } else { (q, r) = y.0.fastDividingFullWidth((x.0, (x.1 as! Magnitude))) } // Now refine q by considering x.2 and y.1. // Note that since y is normalized, q * y - x is between 0 and 2. let (ph, pl) = q.multipliedFullWidth(by: y.1) if ph < r || (ph == r && pl <= x.2) { return q } let (r1, ro) = r.addingReportingOverflow(y.0) if ro { return q - 1 } let (pl1, so) = pl.subtractingReportingOverflow((y.1 as! Magnitude)) let ph1 = (so ? ph - 1 : ph) if ph1 < r1 || (ph1 == r1 && pl1 <= x.2) { return q - 1 } return q - 2 } } extension CS.BigUInt { //MARK: Division /// Divide this integer by the word `y`, leaving the quotient in its place and returning the remainder. /// /// - Requires: y > 0 /// - Complexity: O(count) internal mutating func divide(byWord y: Word) -> Word { precondition(y > 0) if y == 1 { return 0 } var remainder: Word = 0 for i in (0 ..< count).reversed() { let u = self[i] (self[i], remainder) = y.fastDividingFullWidth((remainder, u)) } return remainder } /// Divide this integer by the word `y` and return the resulting quotient and remainder. /// /// - Requires: y > 0 /// - Returns: (quotient, remainder) where quotient = floor(x/y), remainder = x - quotient * y /// - Complexity: O(x.count) internal func quotientAndRemainder(dividingByWord y: Word) -> (quotient: CS.BigUInt, remainder: Word) { var div = self let mod = div.divide(byWord: y) return (div, mod) } /// Divide `x` by `y`, putting the quotient in `x` and the remainder in `y`. /// Reusing integers like this reduces the number of allocations during the calculation. static func divide(_ x: inout CS.BigUInt, by y: inout CS.BigUInt) { // This is a Swift adaptation of "divmnu" from Hacker's Delight, which is in // turn a C adaptation of Knuth's Algorithm D (TAOCP vol 2, 4.3.1). precondition(!y.isZero) // First, let's take care of the easy cases. if x < y { (x, y) = (0, x) return } if y.count == 1 { // The single-word case reduces to a simpler loop. y = CS.BigUInt(x.divide(byWord: y[0])) return } // In the hard cases, we will perform the long division algorithm we learned in school. // It works by successively calculating the single-word quotient of the top y.count + 1 // words of x divided by y, replacing the top of x with the remainder, and repeating // the process one word lower. // // The tricky part is that the algorithm needs to be able to do n+1/n word divisions, // but we only have a primitive for dividing two words by a single // word. (Remember that this step is also tricky when we do it on paper!) // // The solution is that the long division can be approximated by a single full division // using just the most significant words. We can then use multiplications and // subtractions to refine the approximation until we get the correct quotient word. // // We could do this by doing a simple 2/1 full division, but Knuth goes one step further, // and implements a 3/2 division. This results in an exact approximation in the // vast majority of cases, eliminating an extra subtraction over big integers. // // The function `approximateQuotient` above implements Knuth's 3/2 division algorithm. // It requires that the divisor's most significant word is larger than // Word.max / 2. This ensures that the approximation has tiny error bounds, // which is what makes this entire approach viable. // To satisfy this requirement, we will normalize the division by multiplying // both the divisor and the dividend by the same (small) factor. let z = y.leadingZeroBitCount y <<= z x <<= z // We'll calculate the remainder in the normalized dividend. var quotient = CS.BigUInt() assert(y.leadingZeroBitCount == 0) // We're ready to start the long division! let dc = y.count let d1 = y[dc - 1] let d0 = y[dc - 2] var product: CS.BigUInt = 0 for j in (dc ... x.count).reversed() { // Approximate dividing the top dc+1 words of `remainder` using the topmost 3/2 words. let r2 = x[j] let r1 = x[j - 1] let r0 = x[j - 2] let q = Word.approximateQuotient(dividing: (r2, r1, r0), by: (d1, d0)) // Multiply the entire divisor with `q` and subtract the result from remainder. // Normalization ensures the 3/2 quotient will either be exact for the full division, or // it may overshoot by at most 1, in which case the product will be greater // than the remainder. product.load(y) product.multiply(byWord: q) if product <= x.extract(j - dc ..< j + 1) { x.subtract(product, shiftedBy: j - dc) quotient[j - dc] = q } else { // This case is extremely rare -- it has a probability of 1/2^(Word.bitWidth - 1). x.add(y, shiftedBy: j - dc) x.subtract(product, shiftedBy: j - dc) quotient[j - dc] = q - 1 } } // The remainder's normalization needs to be undone, but otherwise we're done. x >>= z y = x x = quotient } /// Divide `x` by `y`, putting the remainder in `x`. mutating func formRemainder(dividingBy y: CS.BigUInt, normalizedBy shift: Int) { precondition(!y.isZero) assert(y.leadingZeroBitCount == 0) if y.count == 1 { let remainder = self.divide(byWord: y[0] >> shift) self.load(CS.BigUInt(remainder)) return } self <<= shift if self >= y { let dc = y.count let d1 = y[dc - 1] let d0 = y[dc - 2] var product: CS.BigUInt = 0 for j in (dc ... self.count).reversed() { let r2 = self[j] let r1 = self[j - 1] let r0 = self[j - 2] let q = Word.approximateQuotient(dividing: (r2, r1, r0), by: (d1, d0)) product.load(y) product.multiply(byWord: q) if product <= self.extract(j - dc ..< j + 1) { self.subtract(product, shiftedBy: j - dc) } else { self.add(y, shiftedBy: j - dc) self.subtract(product, shiftedBy: j - dc) } } } self >>= shift } /// Divide this integer by `y` and return the resulting quotient and remainder. /// /// - Requires: `y > 0` /// - Returns: `(quotient, remainder)` where `quotient = floor(self/y)`, `remainder = self - quotient * y` /// - Complexity: O(count^2) public func quotientAndRemainder(dividingBy y: CS.BigUInt) -> (quotient: CS.BigUInt, remainder: CS.BigUInt) { var x = self var y = y CS.BigUInt.divide(&x, by: &y) return (x, y) } /// Divide `x` by `y` and return the quotient. /// /// - Note: Use `divided(by:)` if you also need the remainder. public static func /(x: CS.BigUInt, y: CS.BigUInt) -> CS.BigUInt { return x.quotientAndRemainder(dividingBy: y).quotient } /// Divide `x` by `y` and return the remainder. /// /// - Note: Use `divided(by:)` if you also need the remainder. public static func %(x: CS.BigUInt, y: CS.BigUInt) -> CS.BigUInt { var x = x let shift = y.leadingZeroBitCount x.formRemainder(dividingBy: y << shift, normalizedBy: shift) return x } /// Divide `x` by `y` and store the quotient in `x`. /// /// - Note: Use `divided(by:)` if you also need the remainder. public static func /=(x: inout CS.BigUInt, y: CS.BigUInt) { var y = y CS.BigUInt.divide(&x, by: &y) } /// Divide `x` by `y` and store the remainder in `x`. /// /// - Note: Use `divided(by:)` if you also need the remainder. public static func %=(x: inout CS.BigUInt, y: CS.BigUInt) { let shift = y.leadingZeroBitCount x.formRemainder(dividingBy: y << shift, normalizedBy: shift) } } extension CS.BigInt { /// Divide this integer by `y` and return the resulting quotient and remainder. /// /// - Requires: `y > 0` /// - Returns: `(quotient, remainder)` where `quotient = floor(self/y)`, `remainder = self - quotient * y` /// - Complexity: O(count^2) public func quotientAndRemainder(dividingBy y: CS.BigInt) -> (quotient: CS.BigInt, remainder: CS.BigInt) { var a = self.magnitude var b = y.magnitude CS.BigUInt.divide(&a, by: &b) return ( CS.BigInt(sign: self.sign == y.sign ? .plus : .minus, magnitude: a), CS.BigInt(sign: self.sign, magnitude: b)) } /// Divide `a` by `b` and return the quotient. Traps if `b` is zero. public static func /(a: CS.BigInt, b: CS.BigInt) -> CS.BigInt { return CS.BigInt(sign: a.sign == b.sign ? .plus : .minus, magnitude: a.magnitude / b.magnitude) } /// Divide `a` by `b` and return the remainder. The result has the same sign as `a`. public static func %(a: CS.BigInt, b: CS.BigInt) -> CS.BigInt { return CS.BigInt(sign: a.sign, magnitude: a.magnitude % b.magnitude) } /// Return the result of `a` mod `b`. The result is always a nonnegative integer that is less than the absolute value of `b`. public func modulus(_ mod: CS.BigInt) -> CS.BigInt { let remainder = self.magnitude % mod.magnitude return CS.BigInt( self.sign == .minus && !remainder.isZero ? mod.magnitude - remainder : remainder) } } extension CS.BigInt { /// Divide `a` by `b` storing the quotient in `a`. public static func /=(a: inout CS.BigInt, b: CS.BigInt) { a = a / b } /// Divide `a` by `b` storing the remainder in `a`. public static func %=(a: inout CS.BigInt, b: CS.BigInt) { a = a % b } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/Exponentiation.swift ================================================ // // Exponentiation.swift // CS.BigInt // // Created by Károly Lőrentey on 2016-01-03. // Copyright © 2016-2017 Károly Lőrentey. // extension CS.BigUInt { //MARK: Exponentiation /// Returns this integer raised to the power `exponent`. /// /// This function calculates the result by [successively squaring the base while halving the exponent][expsqr]. /// /// [expsqr]: https://en.wikipedia.org/wiki/Exponentiation_by_squaring /// /// - Note: This function can be unreasonably expensive for large exponents, which is why `exponent` is /// a simple integer value. If you want to calculate big exponents, you'll probably need to use /// the modulo arithmetic variant. /// - Returns: 1 if `exponent == 0`, otherwise `self` raised to `exponent`. (This implies that `0.power(0) == 1`.) /// - SeeAlso: `BigUInt.power(_:, modulus:)` /// - Complexity: O((exponent * self.count)^log2(3)) or somesuch. The result may require a large amount of memory, too. public func power(_ exponent: Int) -> CS.BigUInt { if exponent == 0 { return 1 } if exponent == 1 { return self } if exponent < 0 { precondition(!self.isZero) return self == 1 ? 1 : 0 } if self <= 1 { return self } var result = CS.BigUInt(1) var b = self var e = exponent while e > 0 { if e & 1 == 1 { result *= b } e >>= 1 b *= b } return result } /// Returns the remainder of this integer raised to the power `exponent` in modulo arithmetic under `modulus`. /// /// Uses the [right-to-left binary method][rtlb]. /// /// [rtlb]: https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method /// /// - Complexity: O(exponent.count * modulus.count^log2(3)) or somesuch public func power(_ exponent: CS.BigUInt, modulus: CS.BigUInt) -> CS.BigUInt { precondition(!modulus.isZero) if modulus == (1 as CS.BigUInt) { return 0 } let shift = modulus.leadingZeroBitCount let normalizedModulus = modulus << shift var result = CS.BigUInt(1) var b = self b.formRemainder(dividingBy: normalizedModulus, normalizedBy: shift) for var e in exponent.words { for _ in 0 ..< Word.bitWidth { if e & 1 == 1 { result *= b result.formRemainder(dividingBy: normalizedModulus, normalizedBy: shift) } e >>= 1 b *= b b.formRemainder(dividingBy: normalizedModulus, normalizedBy: shift) } } return result } } extension CS.BigInt { /// Returns this integer raised to the power `exponent`. /// /// This function calculates the result by [successively squaring the base while halving the exponent][expsqr]. /// /// [expsqr]: https://en.wikipedia.org/wiki/Exponentiation_by_squaring /// /// - Note: This function can be unreasonably expensive for large exponents, which is why `exponent` is /// a simple integer value. If you want to calculate big exponents, you'll probably need to use /// the modulo arithmetic variant. /// - Returns: 1 if `exponent == 0`, otherwise `self` raised to `exponent`. (This implies that `0.power(0) == 1`.) /// - SeeAlso: `BigUInt.power(_:, modulus:)` /// - Complexity: O((exponent * self.count)^log2(3)) or somesuch. The result may require a large amount of memory, too. public func power(_ exponent: Int) -> CS.BigInt { return CS.BigInt(sign: self.sign == .minus && exponent & 1 != 0 ? .minus : .plus, magnitude: self.magnitude.power(exponent)) } /// Returns the remainder of this integer raised to the power `exponent` in modulo arithmetic under `modulus`. /// /// Uses the [right-to-left binary method][rtlb]. /// /// [rtlb]: https://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method /// /// - Complexity: O(exponent.count * modulus.count^log2(3)) or somesuch public func power(_ exponent: CS.BigInt, modulus: CS.BigInt) -> CS.BigInt { precondition(!modulus.isZero) if modulus.magnitude == 1 { return 0 } if exponent.isZero { return 1 } if exponent == 1 { return self.modulus(modulus) } if exponent < 0 { precondition(!self.isZero) guard magnitude == 1 else { return 0 } guard sign == .minus else { return 1 } guard exponent.magnitude[0] & 1 != 0 else { return 1 } return CS.BigInt(modulus.magnitude - 1) } let power = self.magnitude.power(exponent.magnitude, modulus: modulus.magnitude) if self.sign == .plus || exponent.magnitude[0] & 1 == 0 || power.isZero { return CS.BigInt(power) } return CS.BigInt(modulus.magnitude - power) } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/FloatingPointConversion.swift ================================================ // // FloatingPointConversion.swift // CS.BigInt // // Created by Károly Lőrentey on 2017-08-11. // Copyright © 2016-2017 Károly Lőrentey. // extension CS.BigUInt { public init?(exactly source: T) { guard source.isFinite else { return nil } guard !source.isZero else { self = 0; return } guard source.sign == .plus else { return nil } let value = source.rounded(.towardZero) guard value == source else { return nil } assert(value.floatingPointClass == .positiveNormal) assert(value.exponent >= 0) let significand = value.significandBitPattern self = (CS.BigUInt(1) << value.exponent) + CS.BigUInt(significand) >> (T.significandBitCount - Int(value.exponent)) } public init(_ source: T) { self.init(exactly: source.rounded(.towardZero))! } } extension CS.BigInt { public init?(exactly source: T) { switch source.sign{ case .plus: guard let magnitude = CS.BigUInt(exactly: source) else { return nil } self = CS.BigInt(sign: .plus, magnitude: magnitude) case .minus: guard let magnitude = CS.BigUInt(exactly: -source) else { return nil } self = CS.BigInt(sign: .minus, magnitude: magnitude) } } public init(_ source: T) { self.init(exactly: source.rounded(.towardZero))! } } extension BinaryFloatingPoint where RawExponent: FixedWidthInteger, RawSignificand: FixedWidthInteger { public init(_ value: CS.BigInt) { guard !value.isZero else { self = 0; return } let v = value.magnitude let bitWidth = v.bitWidth var exponent = bitWidth - 1 let shift = bitWidth - Self.significandBitCount - 1 var significand = value.magnitude >> (shift - 1) if significand[0] & 3 == 3 { // Handle rounding significand >>= 1 significand += 1 if significand.trailingZeroBitCount >= Self.significandBitCount { exponent += 1 } } else { significand >>= 1 } let bias = 1 << (Self.exponentBitCount - 1) - 1 guard exponent <= bias else { self = Self.infinity; return } significand &= 1 << Self.significandBitCount - 1 self = Self.init(sign: value.sign == .plus ? .plus : .minus, exponentBitPattern: RawExponent(bias + exponent), significandBitPattern: RawSignificand(significand)) } public init(_ value: CS.BigUInt) { self.init(CS.BigInt(sign: .plus, magnitude: value)) } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/GCD.swift ================================================ // // GCD.swift // CS.BigInt // // Created by Károly Lőrentey on 2016-01-03. // Copyright © 2016-2017 Károly Lőrentey. // extension CS.BigUInt { //MARK: Greatest Common Divisor /// Returns the greatest common divisor of `self` and `b`. /// /// - Complexity: O(count^2) where count = max(self.count, b.count) public func greatestCommonDivisor(with b: CS.BigUInt) -> CS.BigUInt { // This is Stein's algorithm: https://en.wikipedia.org/wiki/Binary_GCD_algorithm if self.isZero { return b } if b.isZero { return self } let az = self.trailingZeroBitCount let bz = b.trailingZeroBitCount let twos = Swift.min(az, bz) var (x, y) = (self >> az, b >> bz) if x < y { swap(&x, &y) } while !x.isZero { x >>= x.trailingZeroBitCount if x < y { swap(&x, &y) } x -= y } return y << twos } /// Returns the [multiplicative inverse of this integer in modulo `modulus` arithmetic][inverse], /// or `nil` if there is no such number. /// /// [inverse]: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers /// /// - Returns: If `gcd(self, modulus) == 1`, the value returned is an integer `a < modulus` such that `(a * self) % modulus == 1`. If `self` and `modulus` aren't coprime, the return value is `nil`. /// - Requires: modulus > 1 /// - Complexity: O(count^3) public func inverse(_ modulus: CS.BigUInt) -> CS.BigUInt? { precondition(modulus > 1) var t1 = CS.BigInt(0) var t2 = CS.BigInt(1) var r1 = modulus var r2 = self while !r2.isZero { let quotient = r1 / r2 (t1, t2) = (t2, t1 - CS.BigInt(quotient) * t2) (r1, r2) = (r2, r1 - quotient * r2) } if r1 > 1 { return nil } if t1.sign == .minus { return modulus - t1.magnitude } return t1.magnitude } } extension CS.BigInt { /// Returns the greatest common divisor of `a` and `b`. /// /// - Complexity: O(count^2) where count = max(a.count, b.count) public func greatestCommonDivisor(with b: CS.BigInt) -> CS.BigInt { return CS.BigInt(self.magnitude.greatestCommonDivisor(with: b.magnitude)) } /// Returns the [multiplicative inverse of this integer in modulo `modulus` arithmetic][inverse], /// or `nil` if there is no such number. /// /// [inverse]: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers /// /// - Returns: If `gcd(self, modulus) == 1`, the value returned is an integer `a < modulus` such that `(a * self) % modulus == 1`. If `self` and `modulus` aren't coprime, the return value is `nil`. /// - Requires: modulus.magnitude > 1 /// - Complexity: O(count^3) public func inverse(_ modulus: CS.BigInt) -> CS.BigInt? { guard let inv = self.magnitude.inverse(modulus.magnitude) else { return nil } return CS.BigInt(self.sign == .plus || inv.isZero ? inv : modulus.magnitude - inv) } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/Hashable.swift ================================================ // // Hashable.swift // BigInt // // Created by Károly Lőrentey on 2016-01-03. // Copyright © 2016-2017 Károly Lőrentey. // extension CS.BigUInt: Hashable { //MARK: Hashing /// Append this `BigUInt` to the specified hasher. public func hash(into hasher: inout Hasher) { for word in self.words { hasher.combine(word) } } } extension CS.BigInt: Hashable { /// Append this `BigInt` to the specified hasher. public func hash(into hasher: inout Hasher) { hasher.combine(sign) hasher.combine(magnitude) } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/IntegerConversion.swift ================================================ // // IntegerConversion.swift // CS.BigInt // // Created by Károly Lőrentey on 2017-08-11. // Copyright © 2016-2017 Károly Lőrentey. // extension CS.BigUInt { public init?(exactly source: T) { guard source >= (0 as T) else { return nil } if source.bitWidth <= 2 * Word.bitWidth { var it = source.words.makeIterator() self.init(low: it.next() ?? 0, high: it.next() ?? 0) precondition(it.next() == nil, "Length of BinaryInteger.words is greater than its bitWidth") } else { self.init(words: source.words) } } public init(_ source: T) { precondition(source >= (0 as T), "BigUInt cannot represent negative values") self.init(exactly: source)! } public init(truncatingIfNeeded source: T) { self.init(words: source.words) } public init(clamping source: T) { if source <= (0 as T) { self.init() } else { self.init(words: source.words) } } } extension CS.BigInt { public init() { self.init(sign: .plus, magnitude: 0) } /// Initializes a new signed big integer with the same value as the specified unsigned big integer. public init(_ integer: CS.BigUInt) { self.magnitude = integer self.sign = .plus } public init(_ source: T) where T : BinaryInteger { if source >= (0 as T) { self.init(sign: .plus, magnitude: CS.BigUInt(source)) } else { var words = Array(source.words) words.twosComplement() self.init(sign: .minus, magnitude: CS.BigUInt(words: words)) } } public init?(exactly source: T) where T : BinaryInteger { self.init(source) } public init(clamping source: T) where T : BinaryInteger { self.init(source) } public init(truncatingIfNeeded source: T) where T : BinaryInteger { self.init(source) } } extension CS.BigUInt: ExpressibleByIntegerLiteral { /// Initialize a new big integer from an integer literal. public init(integerLiteral value: UInt64) { self.init(value) } } extension CS.BigInt: ExpressibleByIntegerLiteral { /// Initialize a new big integer from an integer literal. public init(integerLiteral value: Int64) { self.init(value) } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/Multiplication.swift ================================================ // // Multiplication.swift // CS.BigInt // // Created by Károly Lőrentey on 2016-01-03. // Copyright © 2016-2017 Károly Lőrentey. // extension CS.BigUInt { //MARK: Multiplication /// Multiply this big integer by a single word, and store the result in place of the original big integer. /// /// - Complexity: O(count) public mutating func multiply(byWord y: Word) { guard y != 0 else { self = 0; return } guard y != 1 else { return } var carry: Word = 0 let c = self.count for i in 0 ..< c { let (h, l) = self[i].multipliedFullWidth(by: y) let (low, o) = l.addingReportingOverflow(carry) self[i] = low carry = (o ? h + 1 : h) } self[c] = carry } /// Multiply this big integer by a single Word, and return the result. /// /// - Complexity: O(count) public func multiplied(byWord y: Word) -> CS.BigUInt { var r = self r.multiply(byWord: y) return r } /// Multiply `x` by `y`, and add the result to this integer, optionally shifted `shift` words to the left. /// /// - Note: This is the fused multiply/shift/add operation; it is more efficient than doing the components /// individually. (The fused operation doesn't need to allocate space for temporary big integers.) /// - Returns: `self` is set to `self + (x * y) << (shift * 2^Word.bitWidth)` /// - Complexity: O(count) public mutating func multiplyAndAdd(_ x: CS.BigUInt, _ y: Word, shiftedBy shift: Int = 0) { precondition(shift >= 0) guard y != 0 && x.count > 0 else { return } guard y != 1 else { self.add(x, shiftedBy: shift); return } var mulCarry: Word = 0 var addCarry = false let xc = x.count var xi = 0 while xi < xc || addCarry || mulCarry > 0 { let (h, l) = x[xi].multipliedFullWidth(by: y) let (low, o) = l.addingReportingOverflow(mulCarry) mulCarry = (o ? h + 1 : h) let ai = shift + xi let (sum1, so1) = self[ai].addingReportingOverflow(low) if addCarry { let (sum2, so2) = sum1.addingReportingOverflow(1) self[ai] = sum2 addCarry = so1 || so2 } else { self[ai] = sum1 addCarry = so1 } xi += 1 } } /// Multiply this integer by `y` and return the result. /// /// - Note: This uses the naive O(n^2) multiplication algorithm unless both arguments have more than /// `BigUInt.directMultiplicationLimit` words. /// - Complexity: O(n^log2(3)) public func multiplied(by y: CS.BigUInt) -> CS.BigUInt { // This method is mostly defined for symmetry with the rest of the arithmetic operations. return self * y } /// Multiplication switches to an asymptotically better recursive algorithm when arguments have more words than this limit. public static var directMultiplicationLimit: Int = 1024 /// Multiply `a` by `b` and return the result. /// /// - Note: This uses the naive O(n^2) multiplication algorithm unless both arguments have more than /// `BigUInt.directMultiplicationLimit` words. /// - Complexity: O(n^log2(3)) public static func *(x: CS.BigUInt, y: CS.BigUInt) -> CS.BigUInt { let xc = x.count let yc = y.count if xc == 0 { return CS.BigUInt() } if yc == 0 { return CS.BigUInt() } if yc == 1 { return x.multiplied(byWord: y[0]) } if xc == 1 { return y.multiplied(byWord: x[0]) } if Swift.min(xc, yc) <= CS.BigUInt.directMultiplicationLimit { // Long multiplication. let left = (xc < yc ? y : x) let right = (xc < yc ? x : y) var result = CS.BigUInt() for i in (0 ..< right.count).reversed() { result.multiplyAndAdd(left, right[i], shiftedBy: i) } return result } if yc < xc { let (xh, xl) = x.split var r = xl * y r.add(xh * y, shiftedBy: x.middleIndex) return r } else if xc < yc { let (yh, yl) = y.split var r = yl * x r.add(yh * x, shiftedBy: y.middleIndex) return r } let shift = x.middleIndex // Karatsuba multiplication: // x * y = * = (ignoring carry) let (a, b) = x.split let (c, d) = y.split let high = a * c let low = b * d let xp = a >= b let yp = c >= d let xm = (xp ? a - b : b - a) let ym = (yp ? c - d : d - c) let m = xm * ym var r = low r.add(high, shiftedBy: 2 * shift) r.add(low, shiftedBy: shift) r.add(high, shiftedBy: shift) if xp == yp { r.subtract(m, shiftedBy: shift) } else { r.add(m, shiftedBy: shift) } return r } /// Multiply `a` by `b` and store the result in `a`. public static func *=(a: inout CS.BigUInt, b: CS.BigUInt) { a = a * b } } extension CS.BigInt { /// Multiply `a` with `b` and return the result. public static func *(a: CS.BigInt, b: CS.BigInt) -> CS.BigInt { return CS.BigInt(sign: a.sign == b.sign ? .plus : .minus, magnitude: a.magnitude * b.magnitude) } /// Multiply `a` with `b` in place. public static func *=(a: inout CS.BigInt, b: CS.BigInt) { a = a * b } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/PrimeTest.swift ================================================ // // PrimeTest.swift // CS.BigInt // // Created by Károly Lőrentey on 2016-01-04. // Copyright © 2016-2017 Károly Lőrentey. // /// The first several [prime numbers][primes]. /// /// [primes]: https://oeis.org/A000040 let primes: [CS.BigUInt.Word] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41] /// The ith element in this sequence is the smallest composite number that passes the strong probable prime test /// for all of the first (i+1) primes. /// /// This is sequence [A014233](http://oeis.org/A014233) on the [Online Encyclopaedia of Integer Sequences](http://oeis.org). let pseudoPrimes: [CS.BigUInt] = [ /* 2 */ 2_047, /* 3 */ 1_373_653, /* 5 */ 25_326_001, /* 7 */ 3_215_031_751, /* 11 */ 2_152_302_898_747, /* 13 */ 3_474_749_660_383, /* 17 */ 341_550_071_728_321, /* 19 */ 341_550_071_728_321, /* 23 */ 3_825_123_056_546_413_051, /* 29 */ 3_825_123_056_546_413_051, /* 31 */ 3_825_123_056_546_413_051, /* 37 */ "318665857834031151167461", /* 41 */ "3317044064679887385961981", ] extension CS.BigUInt { //MARK: Primality Testing /// Returns true iff this integer passes the [strong probable prime test][sppt] for the specified base. /// /// [sppt]: https://en.wikipedia.org/wiki/Probable_prime public func isStrongProbablePrime(_ base: CS.BigUInt) -> Bool { precondition(base > (1 as CS.BigUInt)) precondition(self > (0 as CS.BigUInt)) let dec = self - 1 let r = dec.trailingZeroBitCount let d = dec >> r var test = base.power(d, modulus: self) if test == 1 || test == dec { return true } if r > 0 { let shift = self.leadingZeroBitCount let normalized = self << shift for _ in 1 ..< r { test *= test test.formRemainder(dividingBy: normalized, normalizedBy: shift) if test == 1 { return false } if test == dec { return true } } } return false } /// Returns true if this integer is probably prime. Returns false if this integer is definitely not prime. /// /// This function performs a probabilistic [Miller-Rabin Primality Test][mrpt], consisting of `rounds` iterations, /// each calculating the strong probable prime test for a random base. The number of rounds is 10 by default, /// but you may specify your own choice. /// /// To speed things up, the function checks if `self` is divisible by the first few prime numbers before /// diving into (slower) Miller-Rabin testing. /// /// Also, when `self` is less than 82 bits wide, `isPrime` does a deterministic test that is guaranteed to /// return a correct result. /// /// [mrpt]: https://en.wikipedia.org/wiki/Miller–Rabin_primality_test public func isPrime(rounds: Int = 10) -> Bool { if count <= 1 && self[0] < 2 { return false } if count == 1 && self[0] < 4 { return true } // Even numbers above 2 aren't prime. if self[0] & 1 == 0 { return false } // Quickly check for small primes. for i in 1 ..< primes.count { let p = primes[i] if self.count == 1 && self[0] == p { return true } if self.quotientAndRemainder(dividingByWord: p).remainder == 0 { return false } } /// Give an exact answer when we can. if self < pseudoPrimes.last! { for i in 0 ..< pseudoPrimes.count { guard isStrongProbablePrime(CS.BigUInt(primes[i])) else { break } if self < pseudoPrimes[i] { // `self` is below the lowest pseudoprime corresponding to the prime bases we tested. It's a prime! return true } } return false } /// Otherwise do as many rounds of random SPPT as required. for _ in 0 ..< rounds { let random = CS.BigUInt.randomInteger(lessThan: self - 2) + 2 guard isStrongProbablePrime(random) else { return false } } // Well, it smells primey to me. return true } } extension CS.BigInt { //MARK: Primality Testing /// Returns true iff this integer passes the [strong probable prime test][sppt] for the specified base. /// /// [sppt]: https://en.wikipedia.org/wiki/Probable_prime public func isStrongProbablePrime(_ base: CS.BigInt) -> Bool { precondition(base.sign == .plus) if self.sign == .minus { return false } return self.magnitude.isStrongProbablePrime(base.magnitude) } /// Returns true if this integer is probably prime. Returns false if this integer is definitely not prime. /// /// This function performs a probabilistic [Miller-Rabin Primality Test][mrpt], consisting of `rounds` iterations, /// each calculating the strong probable prime test for a random base. The number of rounds is 10 by default, /// but you may specify your own choice. /// /// To speed things up, the function checks if `self` is divisible by the first few prime numbers before /// diving into (slower) Miller-Rabin testing. /// /// Also, when `self` is less than 82 bits wide, `isPrime` does a deterministic test that is guaranteed to /// return a correct result. /// /// [mrpt]: https://en.wikipedia.org/wiki/Miller–Rabin_primality_test public func isPrime(rounds: Int = 10) -> Bool { if self.sign == .minus { return false } return self.magnitude.isPrime(rounds: rounds) } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/Random.swift ================================================ // // Random.swift // CS.BigInt // // Created by Károly Lőrentey on 2016-01-04. // Copyright © 2016-2017 Károly Lőrentey. // extension CS.BigUInt { /// Create a big unsigned integer consisting of `width` uniformly distributed random bits. /// /// - Parameter width: The maximum number of one bits in the result. /// - Parameter generator: The source of randomness. /// - Returns: A big unsigned integer less than `1 << width`. public static func randomInteger(withMaximumWidth width: Int, using generator: inout RNG) -> CS.BigUInt { var result = CS.BigUInt.zero var bitsLeft = width var i = 0 let wordsNeeded = (width + Word.bitWidth - 1) / Word.bitWidth if wordsNeeded > 2 { result.reserveCapacity(wordsNeeded) } while bitsLeft >= Word.bitWidth { result[i] = generator.next() i += 1 bitsLeft -= Word.bitWidth } if bitsLeft > 0 { let mask: Word = (1 << bitsLeft) - 1 result[i] = (generator.next() as Word) & mask } return result } /// Create a big unsigned integer consisting of `width` uniformly distributed random bits. /// /// - Note: I use a `SystemRandomGeneratorGenerator` as the source of randomness. /// /// - Parameter width: The maximum number of one bits in the result. /// - Returns: A big unsigned integer less than `1 << width`. public static func randomInteger(withMaximumWidth width: Int) -> CS.BigUInt { var rng = SystemRandomNumberGenerator() return randomInteger(withMaximumWidth: width, using: &rng) } /// Create a big unsigned integer consisting of `width-1` uniformly distributed random bits followed by a one bit. /// /// - Note: If `width` is zero, the result is zero. /// /// - Parameter width: The number of bits required to represent the answer. /// - Parameter generator: The source of randomness. /// - Returns: A random big unsigned integer whose width is `width`. public static func randomInteger(withExactWidth width: Int, using generator: inout RNG) -> CS.BigUInt { // width == 0 -> return 0 because there is no room for a one bit. // width == 1 -> return 1 because there is no room for any random bits. guard width > 1 else { return CS.BigUInt(width) } var result = randomInteger(withMaximumWidth: width - 1, using: &generator) result[(width - 1) / Word.bitWidth] |= 1 << Word((width - 1) % Word.bitWidth) return result } /// Create a big unsigned integer consisting of `width-1` uniformly distributed random bits followed by a one bit. /// /// - Note: If `width` is zero, the result is zero. /// - Note: I use a `SystemRandomGeneratorGenerator` as the source of randomness. /// /// - Returns: A random big unsigned integer whose width is `width`. public static func randomInteger(withExactWidth width: Int) -> CS.BigUInt { var rng = SystemRandomNumberGenerator() return randomInteger(withExactWidth: width, using: &rng) } /// Create a uniformly distributed random unsigned integer that's less than the specified limit. /// /// - Precondition: `limit > 0`. /// /// - Parameter limit: The upper bound on the result. /// - Parameter generator: The source of randomness. /// - Returns: A random big unsigned integer that is less than `limit`. public static func randomInteger(lessThan limit: CS.BigUInt, using generator: inout RNG) -> CS.BigUInt { precondition(limit > 0, "\(#function): 0 is not a valid limit") let width = limit.bitWidth var random = randomInteger(withMaximumWidth: width, using: &generator) while random >= limit { random = randomInteger(withMaximumWidth: width, using: &generator) } return random } /// Create a uniformly distributed random unsigned integer that's less than the specified limit. /// /// - Precondition: `limit > 0`. /// - Note: I use a `SystemRandomGeneratorGenerator` as the source of randomness. /// /// - Parameter limit: The upper bound on the result. /// - Returns: A random big unsigned integer that is less than `limit`. public static func randomInteger(lessThan limit: CS.BigUInt) -> CS.BigUInt { var rng = SystemRandomNumberGenerator() return randomInteger(lessThan: limit, using: &rng) } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/Shifts.swift ================================================ // // Shifts.swift // CS.BigInt // // Created by Károly Lőrentey on 2016-01-03. // Copyright © 2016-2017 Károly Lőrentey. // extension CS.BigUInt { //MARK: Shift Operators internal func shiftedLeft(by amount: Word) -> CS.BigUInt { guard amount > 0 else { return self } let ext = Int(amount / Word(Word.bitWidth)) // External shift amount (new words) let up = Word(amount % Word(Word.bitWidth)) // Internal shift amount (subword shift) let down = Word(Word.bitWidth) - up var result = CS.BigUInt() if up > 0 { var i = 0 var lowbits: Word = 0 while i < self.count || lowbits > 0 { let word = self[i] result[i + ext] = word << up | lowbits lowbits = word >> down i += 1 } } else { for i in 0 ..< self.count { result[i + ext] = self[i] } } return result } internal mutating func shiftLeft(by amount: Word) { guard amount > 0 else { return } let ext = Int(amount / Word(Word.bitWidth)) // External shift amount (new words) let up = Word(amount % Word(Word.bitWidth)) // Internal shift amount (subword shift) let down = Word(Word.bitWidth) - up if up > 0 { var i = 0 var lowbits: Word = 0 while i < self.count || lowbits > 0 { let word = self[i] self[i] = word << up | lowbits lowbits = word >> down i += 1 } } if ext > 0 && self.count > 0 { self.shiftLeft(byWords: ext) } } internal func shiftedRight(by amount: Word) -> CS.BigUInt { guard amount > 0 else { return self } guard amount < self.bitWidth else { return 0 } let ext = Int(amount / Word(Word.bitWidth)) // External shift amount (new words) let down = Word(amount % Word(Word.bitWidth)) // Internal shift amount (subword shift) let up = Word(Word.bitWidth) - down var result = CS.BigUInt() if down > 0 { var highbits: Word = 0 for i in (ext ..< self.count).reversed() { let word = self[i] result[i - ext] = highbits | word >> down highbits = word << up } } else { for i in (ext ..< self.count).reversed() { result[i - ext] = self[i] } } return result } internal mutating func shiftRight(by amount: Word) { guard amount > 0 else { return } guard amount < self.bitWidth else { self.clear(); return } let ext = Int(amount / Word(Word.bitWidth)) // External shift amount (new words) let down = Word(amount % Word(Word.bitWidth)) // Internal shift amount (subword shift) let up = Word(Word.bitWidth) - down if ext > 0 { self.shiftRight(byWords: ext) } if down > 0 { var i = self.count - 1 var highbits: Word = 0 while i >= 0 { let word = self[i] self[i] = highbits | word >> down highbits = word << up i -= 1 } } } public static func >>=(lhs: inout CS.BigUInt, rhs: Other) { if rhs < (0 as Other) { lhs <<= (0 - rhs) } else if rhs >= lhs.bitWidth { lhs.clear() } else { lhs.shiftRight(by: UInt(rhs)) } } public static func <<=(lhs: inout CS.BigUInt, rhs: Other) { if rhs < (0 as Other) { lhs >>= (0 - rhs) return } lhs.shiftLeft(by: Word(exactly: rhs)!) } public static func >>(lhs: CS.BigUInt, rhs: Other) -> CS.BigUInt { if rhs < (0 as Other) { return lhs << (0 - rhs) } if rhs > Word.max { return 0 } return lhs.shiftedRight(by: UInt(rhs)) } public static func <<(lhs: CS.BigUInt, rhs: Other) -> CS.BigUInt { if rhs < (0 as Other) { return lhs >> (0 - rhs) } return lhs.shiftedLeft(by: Word(exactly: rhs)!) } } extension CS.BigInt { func shiftedLeft(by amount: Word) -> CS.BigInt { return CS.BigInt(sign: self.sign, magnitude: self.magnitude.shiftedLeft(by: amount)) } mutating func shiftLeft(by amount: Word) { self.magnitude.shiftLeft(by: amount) } func shiftedRight(by amount: Word) -> CS.BigInt { let m = self.magnitude.shiftedRight(by: amount) return CS.BigInt(sign: self.sign, magnitude: self.sign == .minus && m.isZero ? 1 : m) } mutating func shiftRight(by amount: Word) { magnitude.shiftRight(by: amount) if sign == .minus, magnitude.isZero { magnitude.load(1) } } public static func &<<(left: CS.BigInt, right: CS.BigInt) -> CS.BigInt { return left.shiftedLeft(by: right.words[0]) } public static func &<<=(left: inout CS.BigInt, right: CS.BigInt) { left.shiftLeft(by: right.words[0]) } public static func &>>(left: CS.BigInt, right: CS.BigInt) -> CS.BigInt { return left.shiftedRight(by: right.words[0]) } public static func &>>=(left: inout CS.BigInt, right: CS.BigInt) { left.shiftRight(by: right.words[0]) } public static func <<(lhs: CS.BigInt, rhs: Other) -> CS.BigInt { guard rhs >= (0 as Other) else { return lhs >> (0 - rhs) } return lhs.shiftedLeft(by: Word(rhs)) } public static func <<=(lhs: inout CS.BigInt, rhs: Other) { if rhs < (0 as Other) { lhs >>= (0 - rhs) } else { lhs.shiftLeft(by: Word(rhs)) } } public static func >>(lhs: CS.BigInt, rhs: Other) -> CS.BigInt { guard rhs >= (0 as Other) else { return lhs << (0 - rhs) } return lhs.shiftedRight(by: Word(rhs)) } public static func >>=(lhs: inout CS.BigInt, rhs: Other) { if rhs < (0 as Other) { lhs <<= (0 - rhs) } else { lhs.shiftRight(by: Word(rhs)) } } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/SquareRoot.swift ================================================ // // SquareRoot.swift // CS.BigInt // // Created by Károly Lőrentey on 2016-01-03. // Copyright © 2016-2017 Károly Lőrentey. // //MARK: Square Root extension CS.BigUInt { /// Returns the integer square root of a big integer; i.e., the largest integer whose square isn't greater than `value`. /// /// - Returns: floor(sqrt(self)) public func squareRoot() -> CS.BigUInt { // This implementation uses Newton's method. guard !self.isZero else { return CS.BigUInt() } var x = CS.BigUInt(1) << ((self.bitWidth + 1) / 2) var y: CS.BigUInt = 0 while true { y.load(self) y /= x y += x y >>= 1 if x == y || x == y - 1 { break } x = y } return x } } extension CS.BigInt { /// Returns the integer square root of a big integer; i.e., the largest integer whose square isn't greater than `value`. /// /// - Requires: self >= 0 /// - Returns: floor(sqrt(self)) public func squareRoot() -> CS.BigInt { precondition(self.sign == .plus) return CS.BigInt(sign: .plus, magnitude: self.magnitude.squareRoot()) } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/Strideable.swift ================================================ // // Strideable.swift // CS.BigInt // // Created by Károly Lőrentey on 2017-08-11. // Copyright © 2016-2017 Károly Lőrentey. // extension CS.BigUInt: Strideable { /// A type that can represent the distance between two values ofa `BigUInt`. public typealias Stride = CS.BigInt /// Adds `n` to `self` and returns the result. Traps if the result would be less than zero. public func advanced(by n: CS.BigInt) -> CS.BigUInt { return n.sign == .minus ? self - n.magnitude : self + n.magnitude } /// Returns the (potentially negative) difference between `self` and `other` as a `BigInt`. Never traps. public func distance(to other: CS.BigUInt) -> CS.BigInt { return CS.BigInt(other) - CS.BigInt(self) } } extension CS.BigInt: Strideable { public typealias Stride = CS.BigInt /// Returns `self + n`. public func advanced(by n: Stride) -> CS.BigInt { return self + n } /// Returns `other - self`. public func distance(to other: CS.BigInt) -> Stride { return other - self } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/StringConversion.swift ================================================ // // StringConversion.swift // CS.BigInt // // Created by Károly Lőrentey on 2016-01-03. // Copyright © 2016-2017 Károly Lőrentey. // extension CS.BigUInt { //MARK: String Conversion /// Calculates the number of numerals in a given radix that fit inside a single `Word`. /// /// - Returns: (chars, power) where `chars` is highest that satisfy `radix^chars <= 2^Word.bitWidth`. `power` is zero /// if radix is a power of two; otherwise `power == radix^chars`. fileprivate static func charsPerWord(forRadix radix: Int) -> (chars: Int, power: Word) { var power: Word = 1 var overflow = false var count = 0 while !overflow { let (high,low) = power.multipliedFullWidth(by: Word(radix)) if high > 0 { overflow = true } if !overflow || (high == 1 && low == 0) { count += 1 power = low } } return (count, power) } /// Initialize a big integer from an ASCII representation in a given radix. Numerals above `9` are represented by /// letters from the English alphabet. /// /// - Requires: `radix > 1 && radix < 36` /// - Parameter `text`: A string consisting of characters corresponding to numerals in the given radix. (0-9, a-z, A-Z) /// - Parameter `radix`: The base of the number system to use, or 10 if unspecified. /// - Returns: The integer represented by `text`, or nil if `text` contains a character that does not represent a numeral in `radix`. public init?(_ text: S, radix: Int = 10) { precondition(radix > 1 && radix < 36) guard !text.isEmpty else { return nil } let (charsPerWord, power) = CS.BigUInt.charsPerWord(forRadix: radix) var words: [Word] = [] var end = text.endIndex var start = end var count = 0 while start != text.startIndex { start = text.index(before: start) count += 1 if count == charsPerWord { guard let d = Word.init(text[start ..< end], radix: radix) else { return nil } words.append(d) end = start count = 0 } } if start != end { guard let d = Word.init(text[start ..< end], radix: radix) else { return nil } words.append(d) } if power == 0 { self.init(words: words) } else { self.init() for d in words.reversed() { self.multiply(byWord: power) self.addWord(d) } } } } extension CS.BigInt { /// Initialize a big integer from an ASCII representation in a given radix. Numerals above `9` are represented by /// letters from the English alphabet. /// /// - Requires: `radix > 1 && radix < 36` /// - Parameter `text`: A string optionally starting with "-" or "+" followed by characters corresponding to numerals in the given radix. (0-9, a-z, A-Z) /// - Parameter `radix`: The base of the number system to use, or 10 if unspecified. /// - Returns: The integer represented by `text`, or nil if `text` contains a character that does not represent a numeral in `radix`. public init?(_ text: S, radix: Int = 10) { var magnitude: CS.BigUInt? var sign: Sign = .plus if text.first == "-" { sign = .minus let text = text.dropFirst() magnitude = CS.BigUInt(text, radix: radix) } else if text.first == "+" { let text = text.dropFirst() magnitude = CS.BigUInt(text, radix: radix) } else { magnitude = CS.BigUInt(text, radix: radix) } guard let m = magnitude else { return nil } self.magnitude = m self.sign = m.isZero ? .plus : sign } } extension String { /// Initialize a new string with the base-10 representation of an unsigned big integer. /// /// - Complexity: O(v.count^2) public init(_ v: CS.BigUInt) { self.init(v, radix: 10, uppercase: false) } /// Initialize a new string representing an unsigned big integer in the given radix (base). /// /// Numerals greater than 9 are represented as letters from the English alphabet, /// starting with `a` if `uppercase` is false or `A` otherwise. /// /// - Requires: radix > 1 && radix <= 36 /// - Complexity: O(count) when radix is a power of two; otherwise O(count^2). public init(_ v: CS.BigUInt, radix: Int, uppercase: Bool = false) { precondition(radix > 1) let (charsPerWord, power) = CS.BigUInt.charsPerWord(forRadix: radix) guard !v.isZero else { self = "0"; return } var parts: [String] if power == 0 { parts = v.words.map { String($0, radix: radix, uppercase: uppercase) } } else { parts = [] var rest = v while !rest.isZero { let mod = rest.divide(byWord: power) parts.append(String(mod, radix: radix, uppercase: uppercase)) } } assert(!parts.isEmpty) self = "" var first = true for part in parts.reversed() { let zeroes = charsPerWord - part.count assert(zeroes >= 0) if !first && zeroes > 0 { // Insert leading zeroes for mid-Words self += String(repeating: "0", count: zeroes) } first = false self += part } } /// Initialize a new string representing a signed big integer in the given radix (base). /// /// Numerals greater than 9 are represented as letters from the English alphabet, /// starting with `a` if `uppercase` is false or `A` otherwise. /// /// - Requires: radix > 1 && radix <= 36 /// - Complexity: O(count) when radix is a power of two; otherwise O(count^2). public init(_ value: CS.BigInt, radix: Int = 10, uppercase: Bool = false) { self = String(value.magnitude, radix: radix, uppercase: uppercase) if value.sign == .minus { self = "-" + self } } } extension CS.BigUInt: ExpressibleByStringLiteral { /// Initialize a new big integer from a Unicode scalar. /// The scalar must represent a decimal digit. public init(unicodeScalarLiteral value: UnicodeScalar) { self = CS.BigUInt(String(value), radix: 10)! } /// Initialize a new big integer from an extended grapheme cluster. /// The cluster must consist of a decimal digit. public init(extendedGraphemeClusterLiteral value: String) { self = CS.BigUInt(value, radix: 10)! } /// Initialize a new big integer from a decimal number represented by a string literal of arbitrary length. /// The string must contain only decimal digits. public init(stringLiteral value: StringLiteralType) { self = CS.BigUInt(value, radix: 10)! } } extension CS.BigInt: ExpressibleByStringLiteral { /// Initialize a new big integer from a Unicode scalar. /// The scalar must represent a decimal digit. public init(unicodeScalarLiteral value: UnicodeScalar) { self = CS.BigInt(String(value), radix: 10)! } /// Initialize a new big integer from an extended grapheme cluster. /// The cluster must consist of a decimal digit. public init(extendedGraphemeClusterLiteral value: String) { self = CS.BigInt(value, radix: 10)! } /// Initialize a new big integer from a decimal number represented by a string literal of arbitrary length. /// The string must contain only decimal digits. public init(stringLiteral value: StringLiteralType) { self = CS.BigInt(value, radix: 10)! } } extension CS.BigUInt: CustomStringConvertible { /// Return the decimal representation of this integer. public var description: String { return String(self, radix: 10) } } extension CS.BigInt: CustomStringConvertible { /// Return the decimal representation of this integer. public var description: String { return String(self, radix: 10) } } extension CS.BigUInt: CustomPlaygroundDisplayConvertible { /// Return the playground quick look representation of this integer. public var playgroundDescription: Any { let text = String(self) return text + " (\(self.bitWidth) bits)" } } extension CS.BigInt: CustomPlaygroundDisplayConvertible { /// Return the playground quick look representation of this integer. public var playgroundDescription: Any { let text = String(self) return text + " (\(self.magnitude.bitWidth) bits)" } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/Subtraction.swift ================================================ // // Subtraction.swift // CS.BigInt // // Created by Károly Lőrentey on 2016-01-03. // Copyright © 2016-2017 Károly Lőrentey. // extension CS.BigUInt { //MARK: Subtraction /// Subtract `word` from this integer in place, returning a flag indicating if the operation /// caused an arithmetic overflow. `word` is shifted `shift` words to the left before being subtracted. /// /// - Note: If the result indicates an overflow, then `self` becomes the two's complement of the absolute difference. /// - Complexity: O(count) internal mutating func subtractWordReportingOverflow(_ word: Word, shiftedBy shift: Int = 0) -> Bool { precondition(shift >= 0) var carry: Word = word var i = shift let count = self.count while carry > 0 && i < count { let (d, c) = self[i].subtractingReportingOverflow(carry) self[i] = d carry = (c ? 1 : 0) i += 1 } return carry > 0 } /// Subtract `word` from this integer, returning the difference and a flag that is true if the operation /// caused an arithmetic overflow. `word` is shifted `shift` words to the left before being subtracted. /// /// - Note: If `overflow` is true, then the returned value is the two's complement of the absolute difference. /// - Complexity: O(count) internal func subtractingWordReportingOverflow(_ word: Word, shiftedBy shift: Int = 0) -> (partialValue: CS.BigUInt, overflow: Bool) { var result = self let overflow = result.subtractWordReportingOverflow(word, shiftedBy: shift) return (result, overflow) } /// Subtract a digit `d` from this integer in place. /// `d` is shifted `shift` digits to the left before being subtracted. /// /// - Requires: self >= d * 2^shift /// - Complexity: O(count) internal mutating func subtractWord(_ word: Word, shiftedBy shift: Int = 0) { let overflow = subtractWordReportingOverflow(word, shiftedBy: shift) precondition(!overflow) } /// Subtract a digit `d` from this integer and return the result. /// `d` is shifted `shift` digits to the left before being subtracted. /// /// - Requires: self >= d * 2^shift /// - Complexity: O(count) internal func subtractingWord(_ word: Word, shiftedBy shift: Int = 0) -> CS.BigUInt { var result = self result.subtractWord(word, shiftedBy: shift) return result } /// Subtract `other` from this integer in place, and return a flag indicating if the operation caused an /// arithmetic overflow. `other` is shifted `shift` digits to the left before being subtracted. /// /// - Note: If the result indicates an overflow, then `self` becomes the twos' complement of the absolute difference. /// - Complexity: O(count) public mutating func subtractReportingOverflow(_ b: CS.BigUInt, shiftedBy shift: Int = 0) -> Bool { precondition(shift >= 0) var carry = false var bi = 0 let bc = b.count let count = self.count while bi < bc || (shift + bi < count && carry) { let ai = shift + bi let (d, c) = self[ai].subtractingReportingOverflow(b[bi]) if carry { let (d2, c2) = d.subtractingReportingOverflow(1) self[ai] = d2 carry = c || c2 } else { self[ai] = d carry = c } bi += 1 } return carry } /// Subtract `other` from this integer, returning the difference and a flag indicating arithmetic overflow. /// `other` is shifted `shift` digits to the left before being subtracted. /// /// - Note: If `overflow` is true, then the result value is the twos' complement of the absolute value of the difference. /// - Complexity: O(count) public func subtractingReportingOverflow(_ other: CS.BigUInt, shiftedBy shift: Int) -> (partialValue: CS.BigUInt, overflow: Bool) { var result = self let overflow = result.subtractReportingOverflow(other, shiftedBy: shift) return (result, overflow) } /// Subtracts `other` from `self`, returning the result and a flag indicating arithmetic overflow. /// /// - Note: When the operation overflows, then `partialValue` is the twos' complement of the absolute value of the difference. /// - Complexity: O(count) public func subtractingReportingOverflow(_ other: CS.BigUInt) -> (partialValue: CS.BigUInt, overflow: Bool) { return self.subtractingReportingOverflow(other, shiftedBy: 0) } /// Subtract `other` from this integer in place. /// `other` is shifted `shift` digits to the left before being subtracted. /// /// - Requires: self >= other * 2^shift /// - Complexity: O(count) public mutating func subtract(_ other: CS.BigUInt, shiftedBy shift: Int = 0) { let overflow = subtractReportingOverflow(other, shiftedBy: shift) precondition(!overflow) } /// Subtract `b` from this integer, and return the difference. /// `b` is shifted `shift` digits to the left before being subtracted. /// /// - Requires: self >= b * 2^shift /// - Complexity: O(count) public func subtracting(_ other: CS.BigUInt, shiftedBy shift: Int = 0) -> CS.BigUInt { var result = self result.subtract(other, shiftedBy: shift) return result } /// Decrement this integer by one. /// /// - Requires: !isZero /// - Complexity: O(count) public mutating func decrement(shiftedBy shift: Int = 0) { self.subtract(1, shiftedBy: shift) } /// Subtract `b` from `a` and return the result. /// /// - Requires: a >= b /// - Complexity: O(a.count) public static func -(a: CS.BigUInt, b: CS.BigUInt) -> CS.BigUInt { return a.subtracting(b) } /// Subtract `b` from `a` and store the result in `a`. /// /// - Requires: a >= b /// - Complexity: O(a.count) public static func -=(a: inout CS.BigUInt, b: CS.BigUInt) { a.subtract(b) } } extension CS.BigInt { public mutating func negate() { guard !magnitude.isZero else { return } self.sign = self.sign == .plus ? .minus : .plus } /// Subtract `b` from `a` and return the result. public static func -(a: CS.BigInt, b: CS.BigInt) -> CS.BigInt { return a + -b } /// Subtract `b` from `a` in place. public static func -=(a: inout CS.BigInt, b: CS.BigInt) { a = a - b } } ================================================ FILE: Sources/CryptoSwift/CS_BigInt/WordsAndBits.swift ================================================ // // WordsAndBits.swift // CS.BigInt // // Created by Károly Lőrentey on 2017-08-11. // Copyright © 2016-2017 Károly Lőrentey. // extension Array where Element == UInt { mutating func twosComplement() { var increment = true for i in 0 ..< self.count { if increment { (self[i], increment) = (~self[i]).addingReportingOverflow(1) } else { self[i] = ~self[i] } } } } extension CS.BigUInt { public subscript(bitAt index: Int) -> Bool { get { precondition(index >= 0) let (i, j) = index.quotientAndRemainder(dividingBy: Word.bitWidth) return self[i] & (1 << j) != 0 } set { precondition(index >= 0) let (i, j) = index.quotientAndRemainder(dividingBy: Word.bitWidth) if newValue { self[i] |= 1 << j } else { self[i] &= ~(1 << j) } } } } extension CS.BigUInt { /// The minimum number of bits required to represent this integer in binary. /// /// - Returns: floor(log2(2 * self + 1)) /// - Complexity: O(1) public var bitWidth: Int { guard count > 0 else { return 0 } return count * Word.bitWidth - self[count - 1].leadingZeroBitCount } /// The number of leading zero bits in the binary representation of this integer in base `2^(Word.bitWidth)`. /// This is useful when you need to normalize a `BigUInt` such that the top bit of its most significant word is 1. /// /// - Note: 0 is considered to have zero leading zero bits. /// - Returns: A value in `0...(Word.bitWidth - 1)`. /// - SeeAlso: width /// - Complexity: O(1) public var leadingZeroBitCount: Int { guard count > 0 else { return 0 } return self[count - 1].leadingZeroBitCount } /// The number of trailing zero bits in the binary representation of this integer. /// /// - Note: 0 is considered to have zero trailing zero bits. /// - Returns: A value in `0...width`. /// - Complexity: O(count) public var trailingZeroBitCount: Int { guard count > 0 else { return 0 } let i = self.words.firstIndex { $0 != 0 }! return i * Word.bitWidth + self[i].trailingZeroBitCount } } extension CS.BigInt { public var bitWidth: Int { guard !magnitude.isZero else { return 0 } return magnitude.bitWidth + 1 } public var trailingZeroBitCount: Int { // Amazingly, this works fine for negative numbers return magnitude.trailingZeroBitCount } } extension CS.BigUInt { public struct Words: RandomAccessCollection { private let value: CS.BigUInt fileprivate init(_ value: CS.BigUInt) { self.value = value } public var startIndex: Int { return 0 } public var endIndex: Int { return value.count } public subscript(_ index: Int) -> Word { return value[index] } } public var words: Words { return Words(self) } public init(words: Words) where Words.Element == Word { let uc = words.underestimatedCount if uc > 2 { self.init(words: Array(words)) } else { var it = words.makeIterator() guard let w0 = it.next() else { self.init() return } guard let w1 = it.next() else { self.init(word: w0) return } if let w2 = it.next() { var words: [UInt] = [] words.reserveCapacity(Swift.max(3, uc)) words.append(w0) words.append(w1) words.append(w2) while let word = it.next() { words.append(word) } self.init(words: words) } else { self.init(low: w0, high: w1) } } } } extension CS.BigInt { public struct Words: RandomAccessCollection { public typealias Indices = CountableRange private let value: CS.BigInt private let decrementLimit: Int fileprivate init(_ value: CS.BigInt) { self.value = value switch value.sign { case .plus: self.decrementLimit = 0 case .minus: assert(!value.magnitude.isZero) self.decrementLimit = value.magnitude.words.firstIndex(where: { $0 != 0 })! } } public var count: Int { switch value.sign { case .plus: if let high = value.magnitude.words.last, high >> (Word.bitWidth - 1) != 0 { return value.magnitude.count + 1 } return value.magnitude.count case .minus: let high = value.magnitude.words.last! if high >> (Word.bitWidth - 1) != 0 { return value.magnitude.count + 1 } return value.magnitude.count } } public var indices: Indices { return 0 ..< count } public var startIndex: Int { return 0 } public var endIndex: Int { return count } public subscript(_ index: Int) -> UInt { // Note that indices above `endIndex` are accepted. if value.sign == .plus { return value.magnitude[index] } if index <= decrementLimit { return ~(value.magnitude[index] &- 1) } return ~value.magnitude[index] } } public var words: Words { return Words(self) } public init(words: S) where S.Element == Word { var words = Array(words) if (words.last ?? 0) >> (Word.bitWidth - 1) == 0 { self.init(sign: .plus, magnitude: CS.BigUInt(words: words)) } else { words.twosComplement() self.init(sign: .minus, magnitude: CS.BigUInt(words: words)) } } } ================================================ FILE: Sources/CryptoSwift/ChaCha20.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // https://tools.ietf.org/html/rfc7539 // public final class ChaCha20: BlockCipher { public enum Error: Swift.Error { case invalidKeyOrInitializationVector case notSupported } public static let blockSize = 64 // 512 / 8 public let keySize: Int fileprivate let key: Key fileprivate var counter: Array public convenience init(key: Array, iv nonce: Array) throws { try self.init(key: key, iv: nonce, blockCounter: 0) } init(key: Array, iv nonce: Array, blockCounter: UInt32 = 0) throws { precondition(nonce.count == 12 || nonce.count == 8) if key.count != 32 { throw Error.invalidKeyOrInitializationVector } self.key = Key(bytes: key) self.keySize = self.key.count if nonce.count == 8 { self.counter = blockCounter.bigEndian.bytes() + [0, 0, 0, 0] + nonce } else { self.counter = blockCounter.bigEndian.bytes() + nonce } assert(self.counter.count == 16) } /// https://tools.ietf.org/html/rfc7539#section-2.3. fileprivate func core(block: inout Array, counter: Array, key: Array) { precondition(block.count == ChaCha20.blockSize) precondition(counter.count == 16) precondition(key.count == 32) let j0: UInt32 = 0x61707865 let j1: UInt32 = 0x3320646e // 0x3620646e sigma/tau let j2: UInt32 = 0x79622d32 let j3: UInt32 = 0x6b206574 let j4: UInt32 = UInt32(bytes: key[0..<4]).bigEndian let j5: UInt32 = UInt32(bytes: key[4..<8]).bigEndian let j6: UInt32 = UInt32(bytes: key[8..<12]).bigEndian let j7: UInt32 = UInt32(bytes: key[12..<16]).bigEndian let j8: UInt32 = UInt32(bytes: key[16..<20]).bigEndian let j9: UInt32 = UInt32(bytes: key[20..<24]).bigEndian let j10: UInt32 = UInt32(bytes: key[24..<28]).bigEndian let j11: UInt32 = UInt32(bytes: key[28..<32]).bigEndian let j12: UInt32 = UInt32(bytes: counter[0..<4]).bigEndian let j13: UInt32 = UInt32(bytes: counter[4..<8]).bigEndian let j14: UInt32 = UInt32(bytes: counter[8..<12]).bigEndian let j15: UInt32 = UInt32(bytes: counter[12..<16]).bigEndian var (x0, x1, x2, x3, x4, x5, x6, x7) = (j0, j1, j2, j3, j4, j5, j6, j7) var (x8, x9, x10, x11, x12, x13, x14, x15) = (j8, j9, j10, j11, j12, j13, j14, j15) for _ in 0..<10 { // 20 rounds x0 = x0 &+ x4 x12 ^= x0 x12 = (x12 << 16) | (x12 >> 16) x8 = x8 &+ x12 x4 ^= x8 x4 = (x4 << 12) | (x4 >> 20) x0 = x0 &+ x4 x12 ^= x0 x12 = (x12 << 8) | (x12 >> 24) x8 = x8 &+ x12 x4 ^= x8 x4 = (x4 << 7) | (x4 >> 25) x1 = x1 &+ x5 x13 ^= x1 x13 = (x13 << 16) | (x13 >> 16) x9 = x9 &+ x13 x5 ^= x9 x5 = (x5 << 12) | (x5 >> 20) x1 = x1 &+ x5 x13 ^= x1 x13 = (x13 << 8) | (x13 >> 24) x9 = x9 &+ x13 x5 ^= x9 x5 = (x5 << 7) | (x5 >> 25) x2 = x2 &+ x6 x14 ^= x2 x14 = (x14 << 16) | (x14 >> 16) x10 = x10 &+ x14 x6 ^= x10 x6 = (x6 << 12) | (x6 >> 20) x2 = x2 &+ x6 x14 ^= x2 x14 = (x14 << 8) | (x14 >> 24) x10 = x10 &+ x14 x6 ^= x10 x6 = (x6 << 7) | (x6 >> 25) x3 = x3 &+ x7 x15 ^= x3 x15 = (x15 << 16) | (x15 >> 16) x11 = x11 &+ x15 x7 ^= x11 x7 = (x7 << 12) | (x7 >> 20) x3 = x3 &+ x7 x15 ^= x3 x15 = (x15 << 8) | (x15 >> 24) x11 = x11 &+ x15 x7 ^= x11 x7 = (x7 << 7) | (x7 >> 25) x0 = x0 &+ x5 x15 ^= x0 x15 = (x15 << 16) | (x15 >> 16) x10 = x10 &+ x15 x5 ^= x10 x5 = (x5 << 12) | (x5 >> 20) x0 = x0 &+ x5 x15 ^= x0 x15 = (x15 << 8) | (x15 >> 24) x10 = x10 &+ x15 x5 ^= x10 x5 = (x5 << 7) | (x5 >> 25) x1 = x1 &+ x6 x12 ^= x1 x12 = (x12 << 16) | (x12 >> 16) x11 = x11 &+ x12 x6 ^= x11 x6 = (x6 << 12) | (x6 >> 20) x1 = x1 &+ x6 x12 ^= x1 x12 = (x12 << 8) | (x12 >> 24) x11 = x11 &+ x12 x6 ^= x11 x6 = (x6 << 7) | (x6 >> 25) x2 = x2 &+ x7 x13 ^= x2 x13 = (x13 << 16) | (x13 >> 16) x8 = x8 &+ x13 x7 ^= x8 x7 = (x7 << 12) | (x7 >> 20) x2 = x2 &+ x7 x13 ^= x2 x13 = (x13 << 8) | (x13 >> 24) x8 = x8 &+ x13 x7 ^= x8 x7 = (x7 << 7) | (x7 >> 25) x3 = x3 &+ x4 x14 ^= x3 x14 = (x14 << 16) | (x14 >> 16) x9 = x9 &+ x14 x4 ^= x9 x4 = (x4 << 12) | (x4 >> 20) x3 = x3 &+ x4 x14 ^= x3 x14 = (x14 << 8) | (x14 >> 24) x9 = x9 &+ x14 x4 ^= x9 x4 = (x4 << 7) | (x4 >> 25) } x0 = x0 &+ j0 x1 = x1 &+ j1 x2 = x2 &+ j2 x3 = x3 &+ j3 x4 = x4 &+ j4 x5 = x5 &+ j5 x6 = x6 &+ j6 x7 = x7 &+ j7 x8 = x8 &+ j8 x9 = x9 &+ j9 x10 = x10 &+ j10 x11 = x11 &+ j11 x12 = x12 &+ j12 x13 = x13 &+ j13 x14 = x14 &+ j14 x15 = x15 &+ j15 block.replaceSubrange(0..<4, with: x0.bigEndian.bytes()) block.replaceSubrange(4..<8, with: x1.bigEndian.bytes()) block.replaceSubrange(8..<12, with: x2.bigEndian.bytes()) block.replaceSubrange(12..<16, with: x3.bigEndian.bytes()) block.replaceSubrange(16..<20, with: x4.bigEndian.bytes()) block.replaceSubrange(20..<24, with: x5.bigEndian.bytes()) block.replaceSubrange(24..<28, with: x6.bigEndian.bytes()) block.replaceSubrange(28..<32, with: x7.bigEndian.bytes()) block.replaceSubrange(32..<36, with: x8.bigEndian.bytes()) block.replaceSubrange(36..<40, with: x9.bigEndian.bytes()) block.replaceSubrange(40..<44, with: x10.bigEndian.bytes()) block.replaceSubrange(44..<48, with: x11.bigEndian.bytes()) block.replaceSubrange(48..<52, with: x12.bigEndian.bytes()) block.replaceSubrange(52..<56, with: x13.bigEndian.bytes()) block.replaceSubrange(56..<60, with: x14.bigEndian.bytes()) block.replaceSubrange(60..<64, with: x15.bigEndian.bytes()) } // XORKeyStream func process(bytes: ArraySlice, counter: inout Array, key: Array) -> Array { precondition(counter.count == 16) precondition(key.count == 32) var block = Array(repeating: 0, count: ChaCha20.blockSize) var bytesSlice = bytes var out = Array(reserveCapacity: bytesSlice.count) while bytesSlice.count >= ChaCha20.blockSize { self.core(block: &block, counter: counter, key: key) for (i, x) in block.enumerated() { out.append(bytesSlice[bytesSlice.startIndex + i] ^ x) } var u: UInt32 = 1 for i in 0..<4 { u += UInt32(counter[i]) counter[i] = UInt8(u & 0xff) u >>= 8 } bytesSlice = bytesSlice[bytesSlice.startIndex + ChaCha20.blockSize..) throws -> Array { self.process(bytes: bytes, counter: &self.counter, key: Array(self.key)) } public func decrypt(_ bytes: ArraySlice) throws -> Array { try self.encrypt(bytes) } } // MARK: Encryptor extension ChaCha20 { public struct ChaChaEncryptor: Cryptor, Updatable { private var accumulated = Array() private let chacha: ChaCha20 init(chacha: ChaCha20) { self.chacha = chacha } public mutating func update(withBytes bytes: ArraySlice, isLast: Bool = false) throws -> Array { self.accumulated += bytes var encrypted = Array() encrypted.reserveCapacity(self.accumulated.count) for chunk in self.accumulated.batched(by: ChaCha20.blockSize) { if isLast || self.accumulated.count >= ChaCha20.blockSize { encrypted += try self.chacha.encrypt(chunk) self.accumulated.removeFirst(chunk.count) // TODO: improve performance } } return encrypted } public func seek(to: Int) throws { throw Error.notSupported } } } // MARK: Decryptor extension ChaCha20 { public struct ChaChaDecryptor: Cryptor, Updatable { private var accumulated = Array() private var offset: Int = 0 private var offsetToRemove: Int = 0 private let chacha: ChaCha20 init(chacha: ChaCha20) { self.chacha = chacha } public mutating func update(withBytes bytes: ArraySlice, isLast: Bool = true) throws -> Array { // prepend "offset" number of bytes at the beginning if self.offset > 0 { self.accumulated += Array(repeating: 0, count: self.offset) + bytes self.offsetToRemove = self.offset self.offset = 0 } else { self.accumulated += bytes } var plaintext = Array() plaintext.reserveCapacity(self.accumulated.count) for chunk in self.accumulated.batched(by: ChaCha20.blockSize) { if isLast || self.accumulated.count >= ChaCha20.blockSize { plaintext += try self.chacha.decrypt(chunk) // remove "offset" from the beginning of first chunk if self.offsetToRemove > 0 { plaintext.removeFirst(self.offsetToRemove) // TODO: improve performance self.offsetToRemove = 0 } self.accumulated.removeFirst(chunk.count) } } return plaintext } public func seek(to: Int) throws { throw Error.notSupported } } } // MARK: Cryptors extension ChaCha20: Cryptors { //TODO: Use BlockEncryptor/BlockDecryptor public func makeEncryptor() -> Cryptor & Updatable { ChaCha20.ChaChaEncryptor(chacha: self) } public func makeDecryptor() -> Cryptor & Updatable { ChaCha20.ChaChaDecryptor(chacha: self) } } ================================================ FILE: Sources/CryptoSwift/Checksum.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // /// CRC - cyclic redundancy check code. public final class Checksum { @usableFromInline static let table32: Array = [ 0x0000_0000, 0x7707_3096, 0xEE0E_612C, 0x9909_51BA, 0x076D_C419, 0x706A_F48F, 0xE963_A535, 0x9E64_95A3, 0x0EDB_8832, 0x79DC_B8A4, 0xE0D5_E91E, 0x97D2_D988, 0x09B6_4C2B, 0x7EB1_7CBD, 0xE7B8_2D07, 0x90BF_1D91, 0x1DB7_1064, 0x6AB0_20F2, 0xF3B9_7148, 0x84BE_41DE, 0x1ADA_D47D, 0x6DDD_E4EB, 0xF4D4_B551, 0x83D3_85C7, 0x136C_9856, 0x646B_A8C0, 0xFD62_F97A, 0x8A65_C9EC, 0x1401_5C4F, 0x6306_6CD9, 0xFA0F_3D63, 0x8D08_0DF5, 0x3B6E_20C8, 0x4C69_105E, 0xD560_41E4, 0xA267_7172, 0x3C03_E4D1, 0x4B04_D447, 0xD20D_85FD, 0xA50A_B56B, 0x35B5_A8FA, 0x42B2_986C, 0xDBBB_C9D6, 0xACBC_F940, 0x32D8_6CE3, 0x45DF_5C75, 0xDCD6_0DCF, 0xABD1_3D59, 0x26D9_30AC, 0x51DE_003A, 0xC8D7_5180, 0xBFD0_6116, 0x21B4_F4B5, 0x56B3_C423, 0xCFBA_9599, 0xB8BD_A50F, 0x2802_B89E, 0x5F05_8808, 0xC60C_D9B2, 0xB10B_E924, 0x2F6F_7C87, 0x5868_4C11, 0xC161_1DAB, 0xB666_2D3D, 0x76DC_4190, 0x01DB_7106, 0x98D2_20BC, 0xEFD5_102A, 0x71B1_8589, 0x06B6_B51F, 0x9FBF_E4A5, 0xE8B8_D433, 0x7807_C9A2, 0x0F00_F934, 0x9609_A88E, 0xE10E_9818, 0x7F6A_0DBB, 0x086D_3D2D, 0x9164_6C97, 0xE663_5C01, 0x6B6B_51F4, 0x1C6C_6162, 0x8565_30D8, 0xF262_004E, 0x6C06_95ED, 0x1B01_A57B, 0x8208_F4C1, 0xF50F_C457, 0x65B0_D9C6, 0x12B7_E950, 0x8BBE_B8EA, 0xFCB9_887C, 0x62DD_1DDF, 0x15DA_2D49, 0x8CD3_7CF3, 0xFBD4_4C65, 0x4DB2_6158, 0x3AB5_51CE, 0xA3BC_0074, 0xD4BB_30E2, 0x4ADF_A541, 0x3DD8_95D7, 0xA4D1_C46D, 0xD3D6_F4FB, 0x4369_E96A, 0x346E_D9FC, 0xAD67_8846, 0xDA60_B8D0, 0x4404_2D73, 0x3303_1DE5, 0xAA0A_4C5F, 0xDD0D_7CC9, 0x5005_713C, 0x2702_41AA, 0xBE0B_1010, 0xC90C_2086, 0x5768_B525, 0x206F_85B3, 0xB966_D409, 0xCE61_E49F, 0x5EDE_F90E, 0x29D9_C998, 0xB0D0_9822, 0xC7D7_A8B4, 0x59B3_3D17, 0x2EB4_0D81, 0xB7BD_5C3B, 0xC0BA_6CAD, 0xEDB8_8320, 0x9ABF_B3B6, 0x03B6_E20C, 0x74B1_D29A, 0xEAD5_4739, 0x9DD2_77AF, 0x04DB_2615, 0x73DC_1683, 0xE363_0B12, 0x9464_3B84, 0x0D6D_6A3E, 0x7A6A_5AA8, 0xE40E_CF0B, 0x9309_FF9D, 0x0A00_AE27, 0x7D07_9EB1, 0xF00F_9344, 0x8708_A3D2, 0x1E01_F268, 0x6906_C2FE, 0xF762_575D, 0x8065_67CB, 0x196C_3671, 0x6E6B_06E7, 0xFED4_1B76, 0x89D3_2BE0, 0x10DA_7A5A, 0x67DD_4ACC, 0xF9B9_DF6F, 0x8EBE_EFF9, 0x17B7_BE43, 0x60B0_8ED5, 0xD6D6_A3E8, 0xA1D1_937E, 0x38D8_C2C4, 0x4FDF_F252, 0xD1BB_67F1, 0xA6BC_5767, 0x3FB5_06DD, 0x48B2_364B, 0xD80D_2BDA, 0xAF0A_1B4C, 0x3603_4AF6, 0x4104_7A60, 0xDF60_EFC3, 0xA867_DF55, 0x316E_8EEF, 0x4669_BE79, 0xCB61_B38C, 0xBC66_831A, 0x256F_D2A0, 0x5268_E236, 0xCC0C_7795, 0xBB0B_4703, 0x2202_16B9, 0x5505_262F, 0xC5BA_3BBE, 0xB2BD_0B28, 0x2BB4_5A92, 0x5CB3_6A04, 0xC2D7_FFA7, 0xB5D0_CF31, 0x2CD9_9E8B, 0x5BDE_AE1D, 0x9B64_C2B0, 0xEC63_F226, 0x756A_A39C, 0x026D_930A, 0x9C09_06A9, 0xEB0E_363F, 0x7207_6785, 0x0500_5713, 0x95BF_4A82, 0xE2B8_7A14, 0x7BB1_2BAE, 0x0CB6_1B38, 0x92D2_8E9B, 0xE5D5_BE0D, 0x7CDC_EFB7, 0x0BDB_DF21, 0x86D3_D2D4, 0xF1D4_E242, 0x68DD_B3F8, 0x1FDA_836E, 0x81BE_16CD, 0xF6B9_265B, 0x6FB0_77E1, 0x18B7_4777, 0x8808_5AE6, 0xFF0F_6A70, 0x6606_3BCA, 0x1101_0B5C, 0x8F65_9EFF, 0xF862_AE69, 0x616B_FFD3, 0x166C_CF45, 0xA00A_E278, 0xD70D_D2EE, 0x4E04_8354, 0x3903_B3C2, 0xA767_2661, 0xD060_16F7, 0x4969_474D, 0x3E6E_77DB, 0xAED1_6A4A, 0xD9D6_5ADC, 0x40DF_0B66, 0x37D8_3BF0, 0xA9BC_AE53, 0xDEBB_9EC5, 0x47B2_CF7F, 0x30B5_FFE9, 0xBDBD_F21C, 0xCABA_C28A, 0x53B3_9330, 0x24B4_A3A6, 0xBAD0_3605, 0xCDD7_0693, 0x54DE_5729, 0x23D9_67BF, 0xB366_7A2E, 0xC461_4AB8, 0x5D68_1B02, 0x2A6F_2B94, 0xB40B_BE37, 0xC30C_8EA1, 0x5A05_DF1B, 0x2D02_EF8D ] @usableFromInline static let table32c: Array = [ 0x0000_0000, 0xF26B_8303, 0xE13B_70F7, 0x1350_F3F4, 0xC79A_971F, 0x35F1_141C, 0x26A1_E7E8, 0xD4CA_64EB, 0x8AD9_58CF, 0x78B2_DBCC, 0x6BE2_2838, 0x9989_AB3B, 0x4D43_CFD0, 0xBF28_4CD3, 0xAC78_BF27, 0x5E13_3C24, 0x105E_C76F, 0xE235_446C, 0xF165_B798, 0x030E_349B, 0xD7C4_5070, 0x25AF_D373, 0x36FF_2087, 0xC494_A384, 0x9A87_9FA0, 0x68EC_1CA3, 0x7BBC_EF57, 0x89D7_6C54, 0x5D1D_08BF, 0xAF76_8BBC, 0xBC26_7848, 0x4E4D_FB4B, 0x20BD_8EDE, 0xD2D6_0DDD, 0xC186_FE29, 0x33ED_7D2A, 0xE727_19C1, 0x154C_9AC2, 0x061C_6936, 0xF477_EA35, 0xAA64_D611, 0x580F_5512, 0x4B5F_A6E6, 0xB934_25E5, 0x6DFE_410E, 0x9F95_C20D, 0x8CC5_31F9, 0x7EAE_B2FA, 0x30E3_49B1, 0xC288_CAB2, 0xD1D8_3946, 0x23B3_BA45, 0xF779_DEAE, 0x0512_5DAD, 0x1642_AE59, 0xE429_2D5A, 0xBA3A_117E, 0x4851_927D, 0x5B01_6189, 0xA96A_E28A, 0x7DA0_8661, 0x8FCB_0562, 0x9C9B_F696, 0x6EF0_7595, 0x417B_1DBC, 0xB310_9EBF, 0xA040_6D4B, 0x522B_EE48, 0x86E1_8AA3, 0x748A_09A0, 0x67DA_FA54, 0x95B1_7957, 0xCBA2_4573, 0x39C9_C670, 0x2A99_3584, 0xD8F2_B687, 0x0C38_D26C, 0xFE53_516F, 0xED03_A29B, 0x1F68_2198, 0x5125_DAD3, 0xA34E_59D0, 0xB01E_AA24, 0x4275_2927, 0x96BF_4DCC, 0x64D4_CECF, 0x7784_3D3B, 0x85EF_BE38, 0xDBFC_821C, 0x2997_011F, 0x3AC7_F2EB, 0xC8AC_71E8, 0x1C66_1503, 0xEE0D_9600, 0xFD5D_65F4, 0x0F36_E6F7, 0x61C6_9362, 0x93AD_1061, 0x80FD_E395, 0x7296_6096, 0xA65C_047D, 0x5437_877E, 0x4767_748A, 0xB50C_F789, 0xEB1F_CBAD, 0x1974_48AE, 0x0A24_BB5A, 0xF84F_3859, 0x2C85_5CB2, 0xDEEE_DFB1, 0xCDBE_2C45, 0x3FD5_AF46, 0x7198_540D, 0x83F3_D70E, 0x90A3_24FA, 0x62C8_A7F9, 0xB602_C312, 0x4469_4011, 0x5739_B3E5, 0xA552_30E6, 0xFB41_0CC2, 0x092A_8FC1, 0x1A7A_7C35, 0xE811_FF36, 0x3CDB_9BDD, 0xCEB0_18DE, 0xDDE0_EB2A, 0x2F8B_6829, 0x82F6_3B78, 0x709D_B87B, 0x63CD_4B8F, 0x91A6_C88C, 0x456C_AC67, 0xB707_2F64, 0xA457_DC90, 0x563C_5F93, 0x082F_63B7, 0xFA44_E0B4, 0xE914_1340, 0x1B7F_9043, 0xCFB5_F4A8, 0x3DDE_77AB, 0x2E8E_845F, 0xDCE5_075C, 0x92A8_FC17, 0x60C3_7F14, 0x7393_8CE0, 0x81F8_0FE3, 0x5532_6B08, 0xA759_E80B, 0xB409_1BFF, 0x4662_98FC, 0x1871_A4D8, 0xEA1A_27DB, 0xF94A_D42F, 0x0B21_572C, 0xDFEB_33C7, 0x2D80_B0C4, 0x3ED0_4330, 0xCCBB_C033, 0xA24B_B5A6, 0x5020_36A5, 0x4370_C551, 0xB11B_4652, 0x65D1_22B9, 0x97BA_A1BA, 0x84EA_524E, 0x7681_D14D, 0x2892_ED69, 0xDAF9_6E6A, 0xC9A9_9D9E, 0x3BC2_1E9D, 0xEF08_7A76, 0x1D63_F975, 0x0E33_0A81, 0xFC58_8982, 0xB215_72C9, 0x407E_F1CA, 0x532E_023E, 0xA145_813D, 0x758F_E5D6, 0x87E4_66D5, 0x94B4_9521, 0x66DF_1622, 0x38CC_2A06, 0xCAA7_A905, 0xD9F7_5AF1, 0x2B9C_D9F2, 0xFF56_BD19, 0x0D3D_3E1A, 0x1E6D_CDEE, 0xEC06_4EED, 0xC38D_26C4, 0x31E6_A5C7, 0x22B6_5633, 0xD0DD_D530, 0x0417_B1DB, 0xF67C_32D8, 0xE52C_C12C, 0x1747_422F, 0x4954_7E0B, 0xBB3F_FD08, 0xA86F_0EFC, 0x5A04_8DFF, 0x8ECE_E914, 0x7CA5_6A17, 0x6FF5_99E3, 0x9D9E_1AE0, 0xD3D3_E1AB, 0x21B8_62A8, 0x32E8_915C, 0xC083_125F, 0x1449_76B4, 0xE622_F5B7, 0xF572_0643, 0x0719_8540, 0x590A_B964, 0xAB61_3A67, 0xB831_C993, 0x4A5A_4A90, 0x9E90_2E7B, 0x6CFB_AD78, 0x7FAB_5E8C, 0x8DC0_DD8F, 0xE330_A81A, 0x115B_2B19, 0x020B_D8ED, 0xF060_5BEE, 0x24AA_3F05, 0xD6C1_BC06, 0xC591_4FF2, 0x37FA_CCF1, 0x69E9_F0D5, 0x9B82_73D6, 0x88D2_8022, 0x7AB9_0321, 0xAE73_67CA, 0x5C18_E4C9, 0x4F48_173D, 0xBD23_943E, 0xF36E_6F75, 0x0105_EC76, 0x1255_1F82, 0xE03E_9C81, 0x34F4_F86A, 0xC69F_7B69, 0xD5CF_889D, 0x27A4_0B9E, 0x79B7_37BA, 0x8BDC_B4B9, 0x988C_474D, 0x6AE7_C44E, 0xBE2D_A0A5, 0x4C46_23A6, 0x5F16_D052, 0xAD7D_5351 ] @usableFromInline static let table16: Array = [ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 ] @usableFromInline init() { // } /// Polynomial: 0xEDB88320 (Reversed) - IEEE @inlinable func crc32(_ message: Array, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 { var crc: UInt32 = seed != nil ? seed! : 0xFFFF_FFFF for chunk in message.batched(by: 256) { for b in chunk { let idx = Int((crc ^ UInt32(reflect ? b : reversed(b))) & 0xFF) crc = (crc >> 8) ^ Checksum.table32[idx] } } return (reflect ? crc : reversed(crc)) ^ 0xFFFF_FFFF } /// Polynomial: 0x82F63B78 (Reversed) - Castagnoli @inlinable func crc32c(_ message: Array, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 { var crc: UInt32 = seed != nil ? seed! : 0xFFFF_FFFF for chunk in message.batched(by: 256) { for b in chunk { let idx = Int((crc ^ UInt32(reflect ? b : reversed(b))) & 0xFF) crc = (crc >> 8) ^ Checksum.table32c[idx] } } return (reflect ? crc : reversed(crc)) ^ 0xFFFF_FFFF } /// Polynomial: 0xA001 (Reversed) - IBM @inlinable func crc16(_ message: Array, seed: UInt16? = nil) -> UInt16 { var crc: UInt16 = seed != nil ? seed! : 0x0000 for chunk in message.batched(by: 256) { for b in chunk { crc = (crc >> 8) ^ Checksum.table16[Int((crc ^ UInt16(b)) & 0xFF)] } } return crc } } // MARK: Public interface public extension Checksum { /// Calculate CRC32. /// /// - parameter message: Message /// - parameter seed: Seed value (Optional) /// - parameter reflect: is reflect (default true) /// /// - returns: Calculated code @inlinable static func crc32(_ message: Array, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 { Checksum().crc32(message, seed: seed, reflect: reflect) } /// Calculate CRC32C /// /// - parameter message: Message /// - parameter seed: Seed value (Optional) /// - parameter reflect: is reflect (default true) /// /// - returns: Calculated code @inlinable static func crc32c(_ message: Array, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 { Checksum().crc32c(message, seed: seed, reflect: reflect) } /// Calculate CRC16 /// /// - parameter message: Message /// - parameter seed: Seed value (Optional) /// /// - returns: Calculated code @inlinable static func crc16(_ message: Array, seed: UInt16? = nil) -> UInt16 { Checksum().crc16(message, seed: seed) } } ================================================ FILE: Sources/CryptoSwift/Cipher.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public enum CipherError: Error { case encrypt case decrypt } public protocol Cipher: AnyObject { var keySize: Int { get } /// Encrypt given bytes at once /// /// - parameter bytes: Plaintext data /// - returns: Encrypted data func encrypt(_ bytes: ArraySlice) throws -> Array func encrypt(_ bytes: Array) throws -> Array /// Decrypt given bytes at once /// /// - parameter bytes: Ciphertext data /// - returns: Plaintext data func decrypt(_ bytes: ArraySlice) throws -> Array func decrypt(_ bytes: Array) throws -> Array } extension Cipher { public func encrypt(_ bytes: Array) throws -> Array { try self.encrypt(bytes.slice) } public func decrypt(_ bytes: Array) throws -> Array { try self.decrypt(bytes.slice) } } ================================================ FILE: Sources/CryptoSwift/Collection+Extension.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // extension Collection where Self.Element == UInt8, Self.Index == Int { // Big endian order @inlinable func toUInt32Array() -> Array { guard !isEmpty else { return [] } let c = strideCount(from: startIndex, to: endIndex, by: 4) return Array(unsafeUninitializedCapacity: c) { buf, count in var counter = 0 for idx in stride(from: startIndex, to: endIndex, by: 4) { let val = UInt32(bytes: self, fromIndex: idx).bigEndian buf[counter] = val counter += 1 } count = counter assert(counter == c) } } // Big endian order @inlinable func toUInt64Array() -> Array { guard !isEmpty else { return [] } let c = strideCount(from: startIndex, to: endIndex, by: 8) return Array(unsafeUninitializedCapacity: c) { buf, count in var counter = 0 for idx in stride(from: startIndex, to: endIndex, by: 8) { let val = UInt64(bytes: self, fromIndex: idx).bigEndian buf[counter] = val counter += 1 } count = counter assert(counter == c) } } } @usableFromInline func strideCount(from: Int, to: Int, by: Int) -> Int { let count = to - from return count / by + (count % by > 0 ? 1 : 0) } ================================================ FILE: Sources/CryptoSwift/CompactMap.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // #if swift(>=4.1) // TODO: remove this file when Xcode 9.2 is no longer used #else extension Sequence { @inlinable public func compactMap(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] { try flatMap(transform) } } #endif ================================================ FILE: Sources/CryptoSwift/Cryptor.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // /// Cryptor (Encryptor or Decryptor) public protocol Cryptor { /// Seek to position in file, if block mode allows random access. /// /// - parameter to: new value of counter mutating func seek(to: Int) throws } ================================================ FILE: Sources/CryptoSwift/Cryptors.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // #if canImport(Darwin) import Darwin #elseif canImport(Android) import Android #elseif canImport(Glibc) import Glibc #elseif canImport(Musl) import Musl #elseif canImport(ucrt) import ucrt #endif /// Worker cryptor/decryptor of `Updatable` types public protocol Cryptors: AnyObject { /// Cryptor suitable for encryption func makeEncryptor() throws -> Cryptor & Updatable /// Cryptor suitable for decryption func makeDecryptor() throws -> Cryptor & Updatable /// Generate array of random bytes. Helper function. static func randomIV(_ blockSize: Int) -> Array } extension Cryptors { /// Generate array of random values. /// Convenience helper that uses `Swift.RandomNumberGenerator`. /// - Parameter count: Length of array public static func randomIV(_ count: Int) -> Array { (0.. // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // @available(*, renamed: "Digest") public typealias Hash = Digest /// Hash functions to calculate Digest. public struct Digest { /// Calculate MD5 Digest /// - parameter bytes: input message /// - returns: Digest bytes public static func md5(_ bytes: Array) -> Array { MD5().calculate(for: bytes) } /// Calculate SHA1 Digest /// - parameter bytes: input message /// - returns: Digest bytes public static func sha1(_ bytes: Array) -> Array { SHA1().calculate(for: bytes) } /// Calculate SHA2-224 Digest /// - parameter bytes: input message /// - returns: Digest bytes public static func sha224(_ bytes: Array) -> Array { self.sha2(bytes, variant: .sha224) } /// Calculate SHA2-256 Digest /// - parameter bytes: input message /// - returns: Digest bytes public static func sha256(_ bytes: Array) -> Array { self.sha2(bytes, variant: .sha256) } /// Calculate SHA2-384 Digest /// - parameter bytes: input message /// - returns: Digest bytes public static func sha384(_ bytes: Array) -> Array { self.sha2(bytes, variant: .sha384) } /// Calculate SHA2-512 Digest /// - parameter bytes: input message /// - returns: Digest bytes public static func sha512(_ bytes: Array) -> Array { self.sha2(bytes, variant: .sha512) } /// Calculate SHA2 Digest /// - parameter bytes: input message /// - parameter variant: SHA-2 variant /// - returns: Digest bytes public static func sha2(_ bytes: Array, variant: SHA2.Variant) -> Array { SHA2(variant: variant).calculate(for: bytes) } /// Calculate SHA3 Digest /// - parameter bytes: input message /// - parameter variant: SHA-3 variant /// - returns: Digest bytes public static func sha3(_ bytes: Array, variant: SHA3.Variant) -> Array { SHA3(variant: variant).calculate(for: bytes) } } ================================================ FILE: Sources/CryptoSwift/DigestType.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // internal protocol DigestType { func calculate(for bytes: Array) -> Array } ================================================ FILE: Sources/CryptoSwift/Foundation/AES+Foundation.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation extension AES { /// Initialize with CBC block mode. /// /// - Parameters: /// - key: Key as a String. /// - iv: IV as a String. /// - padding: Padding /// - Throws: Error /// /// The input is a String, that is treat as sequence of bytes made directly out of String. /// If input is Base64 encoded data (which is a String technically) it is not decoded automatically for you. public convenience init(key: String, iv: String, padding: Padding = .pkcs7) throws { try self.init(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: padding) } } ================================================ FILE: Sources/CryptoSwift/Foundation/Array+Foundation.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation public extension Array where Element == UInt8 { func toBase64(options: Data.Base64EncodingOptions = []) -> String { Data(self).base64EncodedString(options: options) } init(base64: String, options: Data.Base64DecodingOptions = .ignoreUnknownCharacters) { self.init() guard let decodedData = Data(base64Encoded: base64, options: options) else { return } append(contentsOf: decodedData.byteArray) } } ================================================ FILE: Sources/CryptoSwift/Foundation/Blowfish+Foundation.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation extension Blowfish { /// Initialize with CBC block mode. public convenience init(key: String, iv: String, padding: Padding = .pkcs7) throws { try self.init(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: padding) } } ================================================ FILE: Sources/CryptoSwift/Foundation/ChaCha20+Foundation.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation extension ChaCha20 { public convenience init(key: String, iv: String) throws { try self.init(key: key.bytes, iv: iv.bytes) } } ================================================ FILE: Sources/CryptoSwift/Foundation/Data+Extension.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation extension Data { /// Two octet checksum as defined in RFC-4880. Sum of all octets, mod 65536 public func checksum() -> UInt16 { let s = self.withUnsafeBytes { buf in return buf.lazy.map(UInt32.init).reduce(UInt32(0), +) } return UInt16(s % 65535) } public func md5() -> Data { Data( Digest.md5(byteArray)) } public func sha1() -> Data { Data( Digest.sha1(byteArray)) } public func sha224() -> Data { Data( Digest.sha224(byteArray)) } public func sha256() -> Data { Data( Digest.sha256(byteArray)) } public func sha384() -> Data { Data( Digest.sha384(byteArray)) } public func sha512() -> Data { Data( Digest.sha512(byteArray)) } public func sha3(_ variant: SHA3.Variant) -> Data { Data( Digest.sha3(byteArray, variant: variant)) } public func crc32(seed: UInt32? = nil, reflect: Bool = true) -> Data { Data( Checksum.crc32(byteArray, seed: seed, reflect: reflect).bytes()) } public func crc32c(seed: UInt32? = nil, reflect: Bool = true) -> Data { Data( Checksum.crc32c(byteArray, seed: seed, reflect: reflect).bytes()) } public func crc16(seed: UInt16? = nil) -> Data { Data( Checksum.crc16(byteArray, seed: seed).bytes()) } public func encrypt(cipher: Cipher) throws -> Data { Data( try cipher.encrypt(byteArray.slice)) } public func decrypt(cipher: Cipher) throws -> Data { Data( try cipher.decrypt(byteArray.slice)) } public func authenticate(with authenticator: Authenticator) throws -> Data { Data( try authenticator.authenticate(byteArray)) } } extension Data { public init(hex: String) { self.init(Array(hex: hex)) } public var byteArray: Array { Array(self) } public func toHexString() -> String { self.byteArray.toHexString() } } ================================================ FILE: Sources/CryptoSwift/Foundation/HMAC+Foundation.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation extension HMAC { public convenience init(key: String, variant: HMAC.Variant = .md5) throws { self.init(key: key.bytes, variant: variant) } } ================================================ FILE: Sources/CryptoSwift/Foundation/Rabbit+Foundation.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation extension Rabbit { public convenience init(key: String) throws { try self.init(key: key.bytes) } public convenience init(key: String, iv: String) throws { try self.init(key: key.bytes, iv: iv.bytes) } } ================================================ FILE: Sources/CryptoSwift/Foundation/String+FoundationExtension.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation extension String { /// Return Base64 back to String public func decryptBase64ToString(cipher: Cipher) throws -> String { guard let decodedData = Data(base64Encoded: self, options: []) else { throw CipherError.decrypt } let decrypted = try decodedData.decrypt(cipher: cipher) if let decryptedString = String(data: decrypted, encoding: String.Encoding.utf8) { return decryptedString } throw CipherError.decrypt } public func decryptBase64(cipher: Cipher) throws -> Array { guard let decodedData = Data(base64Encoded: self, options: []) else { throw CipherError.decrypt } return try decodedData.decrypt(cipher: cipher).byteArray } } ================================================ FILE: Sources/CryptoSwift/Foundation/Utils+Foundation.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation func perf(_ text: String, closure: () -> Void) { let measurementStart = Date() closure() let measurementStop = Date() let executionTime = measurementStop.timeIntervalSince(measurementStart) print("\(text) \(executionTime)") } ================================================ FILE: Sources/CryptoSwift/Foundation/XChaCha20+Foundation.swift ================================================ // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation extension XChaCha20 { /// Convenience initializer that creates an XChaCha20 instance with the given key and IV /// represented as hex-encoded strings. /// /// - Parameters: /// - key: The encryption/decryption key as a hex-encoded string. /// - iv: The initialization vector as a hex-encoded string. /// - Throws: An error if the provided key or IV are of invalid length, format, or not hex-encoded. public convenience init(key: String, iv: String) throws { try self.init(key: key.bytes, iv: iv.bytes) } } ================================================ FILE: Sources/CryptoSwift/Generics.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // /// Array of bytes. Caution: don't use directly because generic is slow. /// /// - parameter value: integer value /// - parameter length: length of output array. By default size of value type /// /// - returns: Array of bytes @_specialize(where T == Int) @_specialize(where T == UInt) @_specialize(where T == UInt8) @_specialize(where T == UInt16) @_specialize(where T == UInt32) @_specialize(where T == UInt64) @inlinable func arrayOfBytes(value: T, length totalBytes: Int = MemoryLayout.size) -> Array { let valuePointer = UnsafeMutablePointer.allocate(capacity: 1) valuePointer.pointee = value let bytesPointer = UnsafeMutablePointer(OpaquePointer(valuePointer)) var bytes = Array(repeating: 0, count: totalBytes) for j in 0...size, totalBytes) { bytes[totalBytes - 1 - j] = (bytesPointer + j).pointee } valuePointer.deinitialize(count: 1) valuePointer.deallocate() return bytes } ================================================ FILE: Sources/CryptoSwift/HKDF.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // https://www.ietf.org/rfc/rfc5869.txt // #if canImport(Darwin) import Darwin #elseif canImport(Android) import Android #elseif canImport(Glibc) import Glibc #elseif canImport(Musl) import Musl #elseif canImport(ucrt) import ucrt #elseif canImport(WASILibc) import WASILibc #endif /// A key derivation function. /// /// HKDF - HMAC-based Extract-and-Expand Key Derivation Function. public struct HKDF { public enum Error: Swift.Error { case invalidInput case derivedKeyTooLong } private let numBlocks: Int // l private let dkLen: Int private let info: Array private let prk: Array private let variant: HMAC.Variant /// - parameters: /// - variant: hash variant /// - salt: optional salt (if not provided, it is set to a sequence of variant.digestLength zeros) /// - info: optional context and application specific information /// - keyLength: intended length of derived key public init(password: Array, salt: Array? = nil, info: Array? = nil, keyLength: Int? = nil /* dkLen */, variant: HMAC.Variant = .sha2(.sha256)) throws { guard !password.isEmpty else { throw Error.invalidInput } let dkLen = keyLength ?? variant.digestLength let keyLengthFinal = Double(dkLen) let hLen = Double(variant.digestLength) let numBlocks = Int(ceil(keyLengthFinal / hLen)) // l = ceil(keyLength / hLen) guard numBlocks <= 255 else { throw Error.derivedKeyTooLong } /// HKDF-Extract(salt, password) -> PRK /// - PRK - a pseudo-random key; it is used by calculate() self.prk = try HMAC(key: salt ?? [], variant: variant).authenticate(password) self.info = info ?? [] self.variant = variant self.dkLen = dkLen self.numBlocks = numBlocks } public func calculate() throws -> Array { let hmac = HMAC(key: prk, variant: variant) var ret = Array() ret.reserveCapacity(self.numBlocks * self.variant.digestLength) var value = Array() for i in 1...self.numBlocks { value.append(contentsOf: self.info) value.append(UInt8(i)) let bytes = try hmac.authenticate(value) ret.append(contentsOf: bytes) /// update value to use it as input for next iteration value = bytes } return Array(ret.prefix(self.dkLen)) } public func callAsFunction() throws -> Array { try calculate() } } ================================================ FILE: Sources/CryptoSwift/HMAC.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public final class HMAC: Authenticator { public enum Error: Swift.Error { case authenticateError case invalidInput } public enum Variant { case md5 case sha1 case sha2(SHA2.Variant) case sha3(SHA3.Variant) @available(*, deprecated, message: "Use sha2(variant) instead.") case sha256, sha384, sha512 var digestLength: Int { switch self { case .sha1: return SHA1.digestLength case .sha256: return SHA2.Variant.sha256.digestLength case .sha384: return SHA2.Variant.sha384.digestLength case .sha512: return SHA2.Variant.sha512.digestLength case .sha2(let variant): return variant.digestLength case .sha3(let variant): return variant.digestLength case .md5: return MD5.digestLength } } func calculateHash(_ bytes: Array) -> Array { switch self { case .sha1: return Digest.sha1(bytes) case .sha256: return Digest.sha256(bytes) case .sha384: return Digest.sha384(bytes) case .sha512: return Digest.sha512(bytes) case .sha2(let variant): return Digest.sha2(bytes, variant: variant) case .sha3(let variant): return Digest.sha3(bytes, variant: variant) case .md5: return Digest.md5(bytes) } } func blockSize() -> Int { switch self { case .md5: return MD5.blockSize case .sha1: return SHA1.blockSize case .sha256: return SHA2.Variant.sha256.blockSize case .sha384: return SHA2.Variant.sha384.blockSize case .sha512: return SHA2.Variant.sha512.blockSize case .sha2(let variant): return variant.blockSize case .sha3(let variant): return variant.blockSize } } } var key: Array let variant: Variant public init(key: Array, variant: HMAC.Variant = .md5) { self.variant = variant self.key = key if key.count > variant.blockSize() { let hash = variant.calculateHash(key) self.key = hash } if key.count < variant.blockSize() { self.key = ZeroPadding().add(to: key, blockSize: variant.blockSize()) } } // MARK: Authenticator public func authenticate(_ bytes: Array) throws -> Array { var opad = Array(repeating: 0x5c, count: variant.blockSize()) for idx in self.key.indices { opad[idx] = self.key[idx] ^ opad[idx] } var ipad = Array(repeating: 0x36, count: variant.blockSize()) for idx in self.key.indices { ipad[idx] = self.key[idx] ^ ipad[idx] } let ipadAndMessageHash = self.variant.calculateHash(ipad + bytes) let result = self.variant.calculateHash(opad + ipadAndMessageHash) // return Array(result[0..<10]) // 80 bits return result } } ================================================ FILE: Sources/CryptoSwift/ISO10126Padding.swift ================================================ // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation /// Padding with random bytes, ending with the number of added bytes. /// Read the [Wikipedia](https://en.wikipedia.org/wiki/Padding_(cryptography)#ISO_10126) /// and [Crypto-IT](http://www.crypto-it.net/eng/theory/padding.html) articles for more info. struct ISO10126Padding: PaddingProtocol { init() { } @inlinable func add(to bytes: Array, blockSize: Int) -> Array { let padding = UInt8(blockSize - (bytes.count % blockSize)) var withPadding = bytes if padding > 0 { withPadding += (0..<(padding - 1)).map { _ in UInt8.random(in: 0...255) } + [padding] } return withPadding } @inlinable func remove(from bytes: Array, blockSize: Int?) -> Array { guard !bytes.isEmpty, let lastByte = bytes.last else { return bytes } assert(!bytes.isEmpty, "Need bytes to remove padding") let padding = Int(lastByte) // last byte let finalLength = bytes.count - padding if finalLength < 0 { return bytes } if padding >= 1 { return Array(bytes[0.. // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation // First byte is 0x80, rest is zero padding // http://www.crypto-it.net/eng/theory/padding.html // http://www.embedx.com/pdfs/ISO_STD_7816/info_isoiec7816-4%7Bed21.0%7Den.pdf struct ISO78164Padding: PaddingProtocol { init() { } @inlinable func add(to bytes: Array, blockSize: Int) -> Array { var padded = Array(bytes) padded.append(0x80) while (padded.count % blockSize) != 0 { padded.append(0x00) } return padded } @inlinable func remove(from bytes: Array, blockSize _: Int?) -> Array { if let idx = bytes.lastIndex(of: 0x80) { return Array(bytes[.. // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // #if canImport(Darwin) import Darwin #elseif canImport(Android) import Android #elseif canImport(Glibc) import Glibc #elseif canImport(Musl) import Musl #elseif canImport(ucrt) import ucrt #endif extension FixedWidthInteger { @inlinable func bytes(totalBytes: Int = MemoryLayout.size) -> Array { arrayOfBytes(value: self.littleEndian, length: totalBytes) // TODO: adjust bytes order // var value = self.littleEndian // return withUnsafeBytes(of: &value, Array.init).reversed() } } ================================================ FILE: Sources/CryptoSwift/MD5.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public final class MD5: DigestType { static let blockSize: Int = 64 static let digestLength: Int = 16 // 128 / 8 fileprivate static let hashInitialValue: Array = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476] fileprivate var accumulated = Array() fileprivate var processedBytesTotalCount: Int = 0 fileprivate var accumulatedHash: Array = MD5.hashInitialValue /** specifies the per-round shift amounts */ private let s: Array = [ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 ] /** binary integer part of the sines of integers (Radians) */ private let k: Array = [ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 ] public init() { } public func calculate(for bytes: Array) -> Array { do { return try update(withBytes: bytes.slice, isLast: true) } catch { fatalError() } } public func callAsFunction(_ bytes: Array) -> Array { calculate(for: bytes) } // mutating currentHash in place is way faster than returning new result fileprivate func process(block chunk: ArraySlice, currentHash: inout Array) { assert(chunk.count == 16 * 4) // Initialize hash value for this chunk: var A: UInt32 = currentHash[0] var B: UInt32 = currentHash[1] var C: UInt32 = currentHash[2] var D: UInt32 = currentHash[3] var dTemp: UInt32 = 0 // Main loop for j in 0.., isLast: Bool = false) throws -> Array { self.accumulated += bytes if isLast { let lengthInBits = (processedBytesTotalCount + self.accumulated.count) * 8 let lengthBytes = lengthInBits.bytes(totalBytes: 64 / 8) // A 64-bit representation of b // Step 1. Append padding bitPadding(to: &self.accumulated, blockSize: MD5.blockSize, allowance: 64 / 8) // Step 2. Append Length a 64-bit representation of lengthInBits self.accumulated += lengthBytes.reversed() } var processedBytes = 0 for chunk in self.accumulated.batched(by: MD5.blockSize) { if isLast || (self.accumulated.count - processedBytes) >= MD5.blockSize { self.process(block: chunk, currentHash: &self.accumulatedHash) processedBytes += chunk.count } } self.accumulated.removeFirst(processedBytes) self.processedBytesTotalCount += processedBytes // output current hash var result = Array() result.reserveCapacity(MD5.digestLength) for hElement in self.accumulatedHash { let hLE = hElement.littleEndian result += Array(arrayLiteral: UInt8(hLE & 0xff), UInt8((hLE >> 8) & 0xff), UInt8((hLE >> 16) & 0xff), UInt8((hLE >> 24) & 0xff)) } // reset hash value for instance if isLast { self.accumulatedHash = MD5.hashInitialValue } return result } } ================================================ FILE: Sources/CryptoSwift/NoPadding.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // struct NoPadding: PaddingProtocol { init() { } func add(to data: Array, blockSize _: Int) -> Array { data } func remove(from data: Array, blockSize _: Int?) -> Array { data } } ================================================ FILE: Sources/CryptoSwift/Operators.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // /* Bit shifting with overflow protection using overflow operator "&". Approach is consistent with standard overflow operators &+, &-, &*, &/ and introduce new overflow operators for shifting: &<<, &>> Note: Works with unsigned integers values only Usage var i = 1 // init var j = i &<< 2 //shift left j &<<= 2 //shift left and assign @see: https://medium.com/@krzyzanowskim/swiftly-shift-bits-and-protect-yourself-be33016ce071 This fuctonality is now implemented as part of Swift 3, SE-0104 https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md */ ================================================ FILE: Sources/CryptoSwift/PEM/DER.swift ================================================ // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation /// Conform to this protocol if your type can both be instantiated and expressed as an ASN1 DER representation. internal protocol DERCodable: DERDecodable, DEREncodable { } /// Conform to this protocol if your type can be instantiated from a ASN1 DER representation internal protocol DERDecodable { /// Attempts to instantiate an instance of your Public Key when given a DER representation of your Public Key /// /// - Parameter publicDER: The ASN.1 DER representation of your Public Key init(publicDER: Array) throws /// Attempts to instantiate an instance of your Private Key when given a DER representation of your Private Key /// /// - Parameter privateDER: The ASN.1 DER representation of your Private Key init(privateDER: Array) throws /// Attempts to instantiate a Key when given the ASN1 DER encoded external representation of the Key /// /// - Parameter rawRepresentation: The ASN1 DER Encoded external representation (either public or private) /// - Note: The external representation is identical to that of `SecKeyCopyExternalRepresentation` function from Apple's `Security` framework init(rawRepresentation: Data) throws } /// Conform to this protocol if your type can be described in an ASN1 DER representation internal protocol DEREncodable { /// Returns the DER encoded representation of the Public Key func publicKeyDER() throws -> Array /// Returns the DER encoded representation of the Private Key func privateKeyDER() throws -> Array /// A semantically similar function that mimics the `SecKeyCopyExternalRepresentation` function from Apple's `Security` framework /// - Note: If called on a Private Key, this method will return the Private Keys DER Representation. Likewise, if called on a Public Key, this method will return the Public Keys DER Representation /// - Note: If you'd like to export the Public Keys DER from a Private Key, use the `publicKeyExternalRepresentation()` function func externalRepresentation() throws -> Data /// A semantically similar function that mimics the `SecKeyCopyExternalRepresentation` function from Apple's `Security` framework /// - Note: This function only ever exports the Public Key's DER representation. If called on a Private Key, the corresponding Public Key will be extracted and exported. func publicKeyExternalRepresentation() throws -> Data } struct DER { internal enum Error: Swift.Error { /// We were provided invalid DER data case invalidDERFormat } /// Integer to Octet String Primitive /// - Parameters: /// - x: nonnegative integer to be converted /// - size: intended length of the resulting octet string /// - Returns: corresponding octet string of length xLen /// - Note: https://datatracker.ietf.org/doc/html/rfc3447#section-4.1 internal static func i2osp(x: [UInt8], size: Int) -> [UInt8] { var modulus = x while modulus.count < size { modulus.insert(0x00, at: 0) } if modulus[0] >= 0x80 { modulus.insert(0x00, at: 0) } return modulus } /// Integer to Octet String Primitive /// - Parameters: /// - x: nonnegative integer to be converted /// - size: intended length of the resulting octet string /// - Returns: corresponding octet string of length xLen /// - Note: https://datatracker.ietf.org/doc/html/rfc3447#section-4.1 internal static func i2ospData(x: [UInt8], size: Int) -> Data { return Data(DER.i2osp(x: x, size: size)) } } ================================================ FILE: Sources/CryptoSwift/PKCS/PBKDF1.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public extension PKCS5 { /// A key derivation function. /// /// PBKDF1 is recommended only for compatibility with existing /// applications since the keys it produces may not be large enough for /// some applications. struct PBKDF1 { public enum Error: Swift.Error { case invalidInput case derivedKeyTooLong } public enum Variant { case md5, sha1 @usableFromInline var size: Int { switch self { case .md5: return MD5.digestLength case .sha1: return SHA1.digestLength } } @usableFromInline func calculateHash(_ bytes: Array) -> Array { switch self { case .sha1: return Digest.sha1(bytes) case .md5: return Digest.md5(bytes) } } } @usableFromInline let iterations: Int // c @usableFromInline let variant: Variant @usableFromInline let keyLength: Int @usableFromInline let t1: Array /// - parameters: /// - salt: salt, an eight-bytes /// - variant: hash variant /// - iterations: iteration count, a positive integer /// - keyLength: intended length of derived key public init(password: Array, salt: Array, variant: Variant = .sha1, iterations: Int = 4096 /* c */, keyLength: Int? = nil /* dkLen */ ) throws { precondition(iterations > 0) precondition(salt.count == 8) let keyLength = keyLength ?? variant.size if keyLength > variant.size { throw Error.derivedKeyTooLong } let t1 = variant.calculateHash(password + salt) self.iterations = iterations self.variant = variant self.keyLength = keyLength self.t1 = t1 } /// Apply the underlying hash function Hash for c iterations @inlinable public func calculate() -> Array { var t = self.t1 for _ in 2...self.iterations { t = self.variant.calculateHash(t) } return Array(t[0.. Array { calculate() } } } ================================================ FILE: Sources/CryptoSwift/PKCS/PBKDF2.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // https://www.ietf.org/rfc/rfc2898.txt // #if canImport(Darwin) import Darwin #elseif canImport(Android) import Android #elseif canImport(Glibc) import Glibc #elseif canImport(Musl) import Musl #elseif canImport(ucrt) import ucrt #elseif canImport(WASILibc) import WASILibc #endif public extension PKCS5 { /// A key derivation function. /// /// PBKDF2 - Password-Based Key Derivation Function 2. Key stretching technique. /// DK = PBKDF2(PRF, Password, Salt, c, dkLen) struct PBKDF2 { public enum Error: Swift.Error { case invalidInput case derivedKeyTooLong } private let salt: Array // S fileprivate let iterations: Int // c private let numBlocks: Int // l private let dkLen: Int fileprivate let prf: HMAC /// - parameters: /// - salt: salt /// - variant: hash variant /// - iterations: iteration count, a positive integer /// - keyLength: intended length of derived key /// - variant: MAC variant. Defaults to SHA256 public init(password: Array, salt: Array, iterations: Int = 4096 /* c */, keyLength: Int? = nil /* dkLen */, variant: HMAC.Variant = .sha2(.sha256)) throws { precondition(iterations > 0) let prf = HMAC(key: password, variant: variant) guard iterations > 0 && !salt.isEmpty else { throw Error.invalidInput } self.dkLen = keyLength ?? variant.digestLength let keyLengthFinal = Double(dkLen) let hLen = Double(prf.variant.digestLength) if keyLengthFinal > (pow(2, 32) - 1) * hLen { throw Error.derivedKeyTooLong } self.salt = salt self.iterations = iterations self.prf = prf self.numBlocks = Int(ceil(Double(keyLengthFinal) / hLen)) // l = ceil(keyLength / hLen) } public func calculate() throws -> Array { var ret = Array() ret.reserveCapacity(self.numBlocks * self.prf.variant.digestLength) for i in 1...self.numBlocks { // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter if let value = try calculateBlock(self.salt, blockNum: i) { ret.append(contentsOf: value) } } return Array(ret.prefix(self.dkLen)) } public func callAsFunction() throws -> Array { try calculate() } } } private extension PKCS5.PBKDF2 { func ARR(_ i: Int) -> Array { var inti = Array(repeating: 0, count: 4) inti[0] = UInt8((i >> 24) & 0xff) inti[1] = UInt8((i >> 16) & 0xff) inti[2] = UInt8((i >> 8) & 0xff) inti[3] = UInt8(i & 0xff) return inti } // F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c // U_1 = PRF (P, S || INT (i)) func calculateBlock(_ salt: Array, blockNum: Int) throws -> Array? { guard let u1 = try? prf.authenticate(salt + ARR(blockNum)) else { // blockNum.bytes() is slower return nil } var u = u1 var ret = u if iterations > 1 { // U_2 = PRF (P, U_1) , // U_c = PRF (P, U_{c-1}) . for _ in 2...iterations { u = try prf.authenticate(u) for x in 0.. // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // PKCS is a group of public-key cryptography standards devised // and published by RSA Security Inc, starting in the early 1990s. // /// EMSA PKCS1 v1.5 Padding Scheme /// /// The EMSA Version of the PKCS1 v1.5 padding scheme is **deterministic** (it pads the messages contents with 255 value bytes) /// ``` /// // The returned structure /// // - PS is the applied padding /// // - M is your original Message /// EM = 0x00 || 0x01 || PS || 0x00 || M. /// ``` /// - Note: This Padding scheme is intended to be used for encoding RSA Signatures /// /// [EMSA-PKCS1v1_5 IETF Spec](https://datatracker.ietf.org/doc/html/rfc8017#section-9.2) struct EMSAPKCS1v15Padding: PaddingProtocol { init() { } @inlinable func add(to bytes: Array, blockSize: Int) -> Array { var r = blockSize - ((bytes.count + 3) % blockSize) if r <= 0 { r = blockSize - 3 } return [0x00, 0x01] + Array(repeating: 0xFF, count: r) + [0x00] + bytes } @inlinable func remove(from bytes: Array, blockSize _: Int?) -> Array { assert(!bytes.isEmpty, "Need bytes to remove padding") assert(bytes.prefix(2) == [0x00, 0x01], "Invalid padding prefix") guard let paddingLength = bytes.dropFirst(2).firstIndex(of: 0x00) else { return bytes } guard (paddingLength + 1) <= bytes.count else { return bytes } return Array(bytes[(paddingLength + 1)...]) } } /// EME PKCS1 v1.5 Padding Scheme /// /// The EME Version of the PKCS1 v1.5 padding scheme is **non deterministic** (it pads the messages contents with pseudo-random bytes) /// ``` /// // The returned structure /// // - PS is the applied padding /// // - M is your original Message /// EM = 0x00 || 0x02 || PS || 0x00 || M. /// ``` /// - Note: This Padding scheme is intended to be used for encoding messages before RSA Encryption /// /// [EME-PKCS1v1_5 IETF Spec](https://datatracker.ietf.org/doc/html/rfc8017#section-7.2.1) struct EMEPKCS1v15Padding: PaddingProtocol { init() { } @inlinable func add(to bytes: Array, blockSize: Int) -> Array { var r = blockSize - ((bytes.count + 3) % blockSize) if r <= 0 { r = blockSize - 3 } return [0x00, 0x02] + (0.., blockSize _: Int?) -> Array { assert(!bytes.isEmpty, "Need bytes to remove padding") assert(bytes.prefix(2) == [0x00, 0x02], "Invalid padding prefix") guard let paddingLength = bytes.dropFirst(2).firstIndex(of: 0x00) else { return bytes } guard (paddingLength + 1) <= bytes.count else { return bytes } return Array(bytes[(paddingLength + 1)...]) } } ================================================ FILE: Sources/CryptoSwift/PKCS/PKCS5.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // PKCS is a group of public-key cryptography standards devised // and published by RSA Security Inc, starting in the early 1990s. // public enum PKCS5 { typealias Padding = PKCS7Padding } ================================================ FILE: Sources/CryptoSwift/PKCS/PKCS7.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public enum PKCS7 { typealias Padding = PKCS7Padding } ================================================ FILE: Sources/CryptoSwift/PKCS/PKCS7Padding.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // PKCS is a group of public-key cryptography standards devised // and published by RSA Security Inc, starting in the early 1990s. // struct PKCS7Padding: PaddingProtocol { enum Error: Swift.Error { case invalidPaddingValue } init() { } @inlinable func add(to bytes: Array, blockSize: Int) -> Array { let padding = UInt8(blockSize - (bytes.count % blockSize)) // The value of each added byte is the number of bytes that are added return bytes + Array(repeating: padding, count: Int(padding)) } @inlinable func remove(from bytes: Array, blockSize _: Int?) -> Array { guard !bytes.isEmpty, let lastByte = bytes.last else { return bytes } assert(!bytes.isEmpty, "Need bytes to remove padding") let padding = Int(lastByte) // last byte let finalLength = bytes.count - padding if finalLength < 0 { return bytes } if padding >= 1 { return Array(bytes[0.. // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public protocol PaddingProtocol { func add(to: Array, blockSize: Int) -> Array func remove(from: Array, blockSize: Int?) -> Array } public enum Padding: PaddingProtocol { case noPadding, zeroPadding, pkcs7, pkcs5, eme_pkcs1v15, emsa_pkcs1v15, iso78164, iso10126 public func add(to: Array, blockSize: Int) -> Array { switch self { case .noPadding: return to // NoPadding().add(to: to, blockSize: blockSize) case .zeroPadding: return ZeroPadding().add(to: to, blockSize: blockSize) case .pkcs7: return PKCS7.Padding().add(to: to, blockSize: blockSize) case .pkcs5: return PKCS5.Padding().add(to: to, blockSize: blockSize) case .eme_pkcs1v15: return EMEPKCS1v15Padding().add(to: to, blockSize: blockSize) case .emsa_pkcs1v15: return EMSAPKCS1v15Padding().add(to: to, blockSize: blockSize) case .iso78164: return ISO78164Padding().add(to: to, blockSize: blockSize) case .iso10126: return ISO10126Padding().add(to: to, blockSize: blockSize) } } public func remove(from: Array, blockSize: Int?) -> Array { switch self { case .noPadding: return from //NoPadding().remove(from: from, blockSize: blockSize) case .zeroPadding: return ZeroPadding().remove(from: from, blockSize: blockSize) case .pkcs7: return PKCS7.Padding().remove(from: from, blockSize: blockSize) case .pkcs5: return PKCS5.Padding().remove(from: from, blockSize: blockSize) case .eme_pkcs1v15: return EMEPKCS1v15Padding().remove(from: from, blockSize: blockSize) case .emsa_pkcs1v15: return EMSAPKCS1v15Padding().remove(from: from, blockSize: blockSize) case .iso78164: return ISO78164Padding().remove(from: from, blockSize: blockSize) case .iso10126: return ISO10126Padding().remove(from: from, blockSize: blockSize) } } } ================================================ FILE: Sources/CryptoSwift/Poly1305.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-4 // nacl/crypto_onetimeauth/poly1305/ref/auth.c // /// Poly1305 takes a 32-byte, one-time key and a message and produces a 16-byte tag that authenticates the /// message such that an attacker has a negligible chance of producing a valid tag for an inauthentic message. public final class Poly1305: Authenticator { public enum Error: Swift.Error { case authenticateError } public static let blockSize: Int = 16 private let key: SecureBytes /// - parameter key: 32-byte key public init(key: Array) { self.key = SecureBytes(bytes: key) } private func squeeze(h: inout Array) { assert(h.count == 17) var u: UInt32 = 0 for j in 0..<16 { u = u &+ h[j] h[j] = u & 255 u = u >> 8 } u = u &+ h[16] h[16] = u & 3 u = 5 * (u >> 2) for j in 0..<16 { u = u &+ h[j] h[j] = u & 255 u = u >> 8 } u = u &+ h[16] h[16] = u } private func add(h: inout Array, c: Array) { assert(h.count == 17 && c.count == 17) var u: UInt32 = 0 for j in 0..<17 { u = u &+ (h[j] &+ c[j]) h[j] = u & 255 u = u >> 8 } } private func mulmod(h: inout Array, r: Array) { var hr = Array(repeating: 0, count: 17) var u: UInt32 = 0 for i in 0..<17 { u = 0 for j in 0...i { u = u &+ (h[j] * r[i &- j]) } for j in (i + 1)..<17 { u = u &+ (320 * h[j] * r[i &+ 17 &- j]) } hr[i] = u } h = hr self.squeeze(h: &h) } private func freeze(h: inout Array) { let horig = h self.add(h: &h, c: [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252]) let negative = UInt32(bitPattern: -Int32(h[16] >> 7)) for j in 0..<17 { h[j] ^= negative & (horig[j] ^ h[j]) } } /// the key is partitioned into two parts, called "r" and "s" fileprivate func onetimeauth(message input: Array, key k: Array) -> Array { // clamp var r = Array(repeating: 0, count: 17) var h = Array(repeating: 0, count: 17) var c = Array(repeating: 0, count: 17) r[0] = UInt32(k[0]) r[1] = UInt32(k[1]) r[2] = UInt32(k[2]) r[3] = UInt32(k[3] & 15) r[4] = UInt32(k[4] & 252) r[5] = UInt32(k[5]) r[6] = UInt32(k[6]) r[7] = UInt32(k[7] & 15) r[8] = UInt32(k[8] & 252) r[9] = UInt32(k[9]) r[10] = UInt32(k[10]) r[11] = UInt32(k[11] & 15) r[12] = UInt32(k[12] & 252) r[13] = UInt32(k[13]) r[14] = UInt32(k[14]) r[15] = UInt32(k[15] & 15) r[16] = 0 var inlen = input.count var inpos = 0 while inlen > 0 { for j in 0..) throws -> Array { self.onetimeauth(message: bytes, key: Array(self.key)) } } ================================================ FILE: Sources/CryptoSwift/PrivacyInfo.xcprivacy ================================================ NSPrivacyTracking NSPrivacyTrackingDomains NSPrivacyCollectedDataTypes NSPrivacyAccessedAPITypes ================================================ FILE: Sources/CryptoSwift/RSA/RSA+Cipher.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation // MARK: Cipher extension RSA: Cipher { @inlinable public func encrypt(_ bytes: ArraySlice) throws -> Array { return try self.encrypt(Array(bytes), variant: .pksc1v15) } @inlinable public func encrypt(_ bytes: Array, variant: RSAEncryptionVariant) throws -> Array { // Prepare the data for the specified variant let preparedData = try variant.prepare(bytes, blockSize: self.keySizeBytes) // Encrypt the prepared data return try variant.formatEncryptedBytes(self.encryptPreparedBytes(preparedData), blockSize: self.keySizeBytes) } @inlinable internal func encryptPreparedBytes(_ bytes: Array) throws -> Array { // Calculate encrypted data return BigUInteger(Data(bytes)).power(self.e, modulus: self.n).serialize().byteArray } @inlinable public func decrypt(_ bytes: ArraySlice) throws -> Array { return try self.decrypt(Array(bytes), variant: .pksc1v15) } @inlinable public func decrypt(_ bytes: Array, variant: RSAEncryptionVariant) throws -> Array { // Decrypt the data let decrypted = try self.decryptPreparedBytes(bytes) // Remove padding / unstructure data and return the raw plaintext return variant.removePadding(decrypted, blockSize: self.keySizeBytes) } @inlinable internal func decryptPreparedBytes(_ bytes: Array) throws -> Array { // Check for Private Exponent presence guard let d = d else { throw RSA.Error.noPrivateKey } // Calculate decrypted data return BigUInteger(Data(bytes)).power(d, modulus: self.n).serialize().byteArray } } extension RSA { /// RSA Encryption Block Types /// - [RFC2313 8.1 - Encryption block formatting](https://datatracker.ietf.org/doc/html/rfc2313#section-8.1) @frozen public enum RSAEncryptionVariant { /// The `unsafe` encryption variant, is fully deterministic and doesn't format the inbound data in any way. /// /// - Warning: This is considered an unsafe method of encryption. case unsafe /// The `raw` encryption variant formats the inbound data with a deterministic padding scheme. /// /// - Warning: This is also considered to be an unsafe method of encryption, but matches the `Security` frameworks functionality. case raw /// The `pkcs1v15` encryption variant formats the inbound data with a non deterministic pseudo random padding scheme. /// /// [EME PKCS1v1.5 Padding Scheme Spec](https://datatracker.ietf.org/doc/html/rfc2313#section-8.1) case pksc1v15 @inlinable internal func prepare(_ bytes: Array, blockSize: Int) throws -> Array { switch self { case .unsafe: return bytes case .raw: // We need at least 11 bytes of padding in order to safely encrypt messages // - block types 1 and 2 have this minimum padding requirement, block type 0 isn't specified, but we enforce the minimum padding length here to be safe. guard blockSize >= bytes.count + 11 else { throw RSA.Error.invalidMessageLengthForEncryption } return Array(repeating: 0x00, count: blockSize - bytes.count) + bytes case .pksc1v15: // The `Security` framework refuses to encrypt a zero byte message using the pkcs1v15 padding scheme, so we do the same guard !bytes.isEmpty else { throw RSA.Error.invalidMessageLengthForEncryption } // We need at least 11 bytes of random padding in order to safely encrypt messages (RFC2313 Section 8.1 - Note 6) guard blockSize >= bytes.count + 11 else { throw RSA.Error.invalidMessageLengthForEncryption } return Padding.eme_pkcs1v15.add(to: bytes, blockSize: blockSize) } } @inlinable internal func formatEncryptedBytes(_ bytes: Array, blockSize: Int) -> Array { switch self { case .unsafe: return bytes case .raw, .pksc1v15: // Format the encrypted bytes before returning return Array(repeating: 0x00, count: blockSize - bytes.count) + bytes } } @inlinable internal func removePadding(_ bytes: Array, blockSize: Int) -> Array { switch self { case .unsafe: return bytes case .raw: return bytes case .pksc1v15: // Convert the Octet String into an Integer Primitive using the BigInteger `serialize` method // (this effectively just prefixes the data with a 0x00 byte indicating that its a positive integer) return Padding.eme_pkcs1v15.remove(from: [0x00] + bytes, blockSize: blockSize) } } } } ================================================ FILE: Sources/CryptoSwift/RSA/RSA+Signature.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation // MARK: Signatures & Verification extension RSA: Signature { public func sign(_ bytes: ArraySlice) throws -> Array { try self.sign(Array(bytes), variant: .message_pkcs1v15_SHA256) } /// Signs the data using the Private key and the specified signature variant /// - Parameters: /// - bytes: The data to be signed /// - variant: The variant to use (`digest` variants expect a pre-hashed digest matching that of the specified hash function, `message` variants will hash the data using the specified hash function before signing it) /// - Returns: The signature of the data public func sign(_ bytes: Array, variant: SignatureVariant) throws -> Array { // Check for Private Exponent presence guard let d = d else { throw RSA.Error.noPrivateKey } // Hash & Encode Message let hashedAndEncoded = try RSA.hashedAndEncoded(bytes, variant: variant, keySizeInBytes: self.keySizeBytes) /// Calculate the Signature let signedData = BigUInteger(Data(hashedAndEncoded)).power(d, modulus: self.n).serialize().byteArray return variant.formatSignedBytes(signedData, blockSize: self.keySizeBytes) } public func verify(signature: ArraySlice, for expectedData: ArraySlice) throws -> Bool { try self.verify(signature: Array(signature), for: Array(expectedData), variant: .message_pkcs1v15_SHA256) } /// Verifies whether a Signature is valid for the provided data /// - Parameters: /// - signature: The signature to verify /// - expectedData: The original data that you expected to have been signed /// - variant: The variant used to sign the data /// - Returns: `True` when the signature is valid for the expected data, `False` otherwise. /// /// [IETF Verification Spec](https://datatracker.ietf.org/doc/html/rfc8017#section-8.2.2) public func verify(signature: Array, for bytes: Array, variant: SignatureVariant) throws -> Bool { /// Step 1: Ensure the signature is the same length as the key's modulus guard signature.count == self.keySizeBytes else { throw Error.invalidSignatureLength } /// Prepare the expected message for signature comparison var expectedData = try RSA.hashedAndEncoded(bytes, variant: variant, keySizeInBytes: self.keySizeBytes) if expectedData.count == self.keySizeBytes && expectedData.prefix(1) == [0x00] { expectedData = Array(expectedData.dropFirst()) } /// Step 2: 'Decrypt' the signature let signatureResult = BigUInteger(Data(signature)).power(self.e, modulus: self.n).serialize().byteArray /// Step 3: Compare the 'decrypted' signature with the prepared / encoded expected message.... guard signatureResult == expectedData else { return false } return true } /// Hashes and Encodes a message for signing and verifying /// /// - Note: [EMSA-PKCS1-v1_5](https://datatracker.ietf.org/doc/html/rfc8017#section-9.2) fileprivate static func hashedAndEncoded(_ bytes: [UInt8], variant: SignatureVariant, keySizeInBytes: Int) throws -> Array { /// 1. Apply the hash function to the message M to produce a hash let hashedMessage = variant.calculateHash(bytes) guard variant.enforceLength(hashedMessage, keySizeInBytes: keySizeInBytes) else { throw RSA.Error.invalidMessageLengthForSigning } /// 2. Encode the algorithm ID for the hash function and the hash value into an ASN.1 value of type DigestInfo /// PKCS#1_15 DER Structure (OID == sha256WithRSAEncryption) let t = variant.encode(hashedMessage) if case .raw = variant { return t } /// 3. If emLen < tLen + 11, output "intended encoded message length too short" and stop if keySizeInBytes < t.count + 11 { throw RSA.Error.invalidMessageLengthForSigning } /// 4. Generate an octet string PS consisting of emLen - tLen - 3 /// octets with hexadecimal value 0xff. The length of PS will be /// at least 8 octets. /// 5. Concatenate PS, the DER encoding T, and other padding to form /// the encoded message EM as EM = 0x00 || 0x01 || PS || 0x00 || T. let padded = variant.pad(bytes: t, to: keySizeInBytes) /// Ensure the signature is of the correct length guard padded.count == keySizeInBytes else { throw RSA.Error.invalidMessageLengthForSigning } return padded } } extension RSA { public enum SignatureVariant { /// rsaSignatureRaw case raw /// Hashes the raw message using MD5 before signing the data case message_pkcs1v15_MD5 /// Hashes the raw message using SHA1 before signing the data case message_pkcs1v15_SHA1 /// Hashes the raw message using SHA224 before signing the data case message_pkcs1v15_SHA224 /// Hashes the raw message using SHA256 before signing the data case message_pkcs1v15_SHA256 /// Hashes the raw message using SHA384 before signing the data case message_pkcs1v15_SHA384 /// Hashes the raw message using SHA512 before signing the data case message_pkcs1v15_SHA512 /// Hashes the raw message using SHA512-224 before signing the data case message_pkcs1v15_SHA512_224 /// Hashes the raw message using SHA512-256 before signing the data case message_pkcs1v15_SHA512_256 /// Hashes the raw message using SHA3_256 before signing the data case message_pkcs1v15_SHA3_256 /// Hashes the raw message using SHA3_384 before signing the data case message_pkcs1v15_SHA3_384 /// Hashes the raw message using SHA3_512 before signing the data case message_pkcs1v15_SHA3_512 /// This variant isn't supported yet case digest_pkcs1v15_RAW /// This variant expects that the data to be signed is a valid MD5 Hash Digest case digest_pkcs1v15_MD5 /// This variant expects that the data to be signed is a valid SHA1 Hash Digest case digest_pkcs1v15_SHA1 /// This variant expects that the data to be signed is a valid SHA224 Hash Digest case digest_pkcs1v15_SHA224 /// This variant expects that the data to be signed is a valid SHA256 Hash Digest case digest_pkcs1v15_SHA256 /// This variant expects that the data to be signed is a valid SHA384 Hash Digest case digest_pkcs1v15_SHA384 /// This variant expects that the data to be signed is a valid SHA512 Hash Digest case digest_pkcs1v15_SHA512 /// This variant expects that the data to be signed is a valid SHA512-224 Hash Digest case digest_pkcs1v15_SHA512_224 /// This variant expects that the data to be signed is a valid SHA512-256 Hash Digest case digest_pkcs1v15_SHA512_256 /// This variant expects that the data to be signed is a valid SHA3-256 Hash Digest case digest_pkcs1v15_SHA3_256 /// This variant expects that the data to be signed is a valid SHA3-384 Hash Digest case digest_pkcs1v15_SHA3_384 /// This variant expects that the data to be signed is a valid SHA3-512 Hash Digest case digest_pkcs1v15_SHA3_512 internal var identifier: Array { switch self { case .raw, .digest_pkcs1v15_RAW: return [] case .message_pkcs1v15_MD5, .digest_pkcs1v15_MD5: return Array(arrayLiteral: 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05) case .message_pkcs1v15_SHA1, .digest_pkcs1v15_SHA1: return Array(arrayLiteral: 0x2b, 0x0e, 0x03, 0x02, 0x1a) case .message_pkcs1v15_SHA256, .digest_pkcs1v15_SHA256: return Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01) case .message_pkcs1v15_SHA384, .digest_pkcs1v15_SHA384: return Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02) case .message_pkcs1v15_SHA512, .digest_pkcs1v15_SHA512: return Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03) case .message_pkcs1v15_SHA224, .digest_pkcs1v15_SHA224: return Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04) case .message_pkcs1v15_SHA512_224, .digest_pkcs1v15_SHA512_224: return Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05) case .message_pkcs1v15_SHA512_256, .digest_pkcs1v15_SHA512_256: return Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x06) case .message_pkcs1v15_SHA3_256, .digest_pkcs1v15_SHA3_256: return Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08) case .message_pkcs1v15_SHA3_384, .digest_pkcs1v15_SHA3_384: return Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09) case .message_pkcs1v15_SHA3_512, .digest_pkcs1v15_SHA3_512: return Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0A) } } internal func calculateHash(_ bytes: Array) -> Array { switch self { case .message_pkcs1v15_MD5: return Digest.md5(bytes) case .message_pkcs1v15_SHA1: return Digest.sha1(bytes) case .message_pkcs1v15_SHA224: return Digest.sha224(bytes) case .message_pkcs1v15_SHA256: return Digest.sha256(bytes) case .message_pkcs1v15_SHA384: return Digest.sha384(bytes) case .message_pkcs1v15_SHA512: return Digest.sha512(bytes) case .message_pkcs1v15_SHA512_224: return Digest.sha2(bytes, variant: .sha224) case .message_pkcs1v15_SHA512_256: return Digest.sha2(bytes, variant: .sha256) case .message_pkcs1v15_SHA3_256: return Digest.sha3(bytes, variant: .sha256) case .message_pkcs1v15_SHA3_384: return Digest.sha3(bytes, variant: .sha384) case .message_pkcs1v15_SHA3_512: return Digest.sha3(bytes, variant: .sha512) case .raw, .digest_pkcs1v15_RAW, .digest_pkcs1v15_MD5, .digest_pkcs1v15_SHA1, .digest_pkcs1v15_SHA224, .digest_pkcs1v15_SHA256, .digest_pkcs1v15_SHA384, .digest_pkcs1v15_SHA512, .digest_pkcs1v15_SHA512_224, .digest_pkcs1v15_SHA512_256, .digest_pkcs1v15_SHA3_256, .digest_pkcs1v15_SHA3_384, .digest_pkcs1v15_SHA3_512: return bytes } } internal func enforceLength(_ bytes: Array, keySizeInBytes: Int) -> Bool { switch self { case .raw, .digest_pkcs1v15_RAW: return bytes.count <= keySizeInBytes case .digest_pkcs1v15_MD5: return bytes.count <= 16 case .digest_pkcs1v15_SHA1: return bytes.count <= 20 case .digest_pkcs1v15_SHA224: return bytes.count <= 28 case .digest_pkcs1v15_SHA256, .digest_pkcs1v15_SHA3_256: return bytes.count <= 32 case .digest_pkcs1v15_SHA384, .digest_pkcs1v15_SHA3_384: return bytes.count <= 48 case .digest_pkcs1v15_SHA512, .digest_pkcs1v15_SHA3_512: return bytes.count <= 64 case .digest_pkcs1v15_SHA512_224: return bytes.count <= 28 case .digest_pkcs1v15_SHA512_256: return bytes.count <= 32 case .message_pkcs1v15_MD5, .message_pkcs1v15_SHA1, .message_pkcs1v15_SHA224, .message_pkcs1v15_SHA256, .message_pkcs1v15_SHA384, .message_pkcs1v15_SHA512, .message_pkcs1v15_SHA512_224, .message_pkcs1v15_SHA512_256, .message_pkcs1v15_SHA3_256, .message_pkcs1v15_SHA3_384, .message_pkcs1v15_SHA3_512: return true } } internal func encode(_ bytes: Array) -> Array { switch self { case .raw, .digest_pkcs1v15_RAW: return bytes default: let asn: ASN1.Node = .sequence(nodes: [ .sequence(nodes: [ .objectIdentifier(data: Data(self.identifier)), .null ]), .octetString(data: Data(bytes)) ]) return ASN1.Encoder.encode(asn) } } /// Right now the only Padding Scheme supported is [EMCS-PKCS1v15](https://www.rfc-editor.org/rfc/rfc8017#section-9.2) (others include [EMSA-PSS](https://www.rfc-editor.org/rfc/rfc8017#section-9.1)) internal func pad(bytes: Array, to blockSize: Int) -> Array { switch self { case .raw: return bytes default: return Padding.emsa_pkcs1v15.add(to: bytes, blockSize: blockSize) } } /// Zero pads a signature to the specified block size /// - Parameters: /// - bytes: The signed bytes /// - blockSize: The block size to pad until /// - Returns: A zero padded (prepended) bytes array of length blockSize internal func formatSignedBytes(_ bytes: Array, blockSize: Int) -> Array { switch self { default: // Format the encrypted bytes before returning return Array(repeating: 0x00, count: blockSize - bytes.count) + bytes } } } } ================================================ FILE: Sources/CryptoSwift/RSA/RSA.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // Foundation is required for `Data` to be found import Foundation // Note: The `BigUInt` struct was copied from: // https://github.com/attaswift/BigInt // It allows fast calculation for RSA big numbers public final class RSA: DERCodable { /// RSA Key Errors public enum Error: Swift.Error { /// No private key specified case noPrivateKey /// Failed to calculate the inverse e and phi case invalidInverseNotCoprimes /// We only support Version 0 RSA keys (we don't support Version 1 introduced in RFC 3447) case unsupportedRSAVersion /// Failed to verify primes during initialiization (the provided primes don't reproduce the provided private exponent) case invalidPrimes /// We attempted to export a private key without our underlying primes case noPrimes /// Unable to calculate the coefficient during a private key import / export case unableToCalculateCoefficient /// The signature to verify is of an invalid length case invalidSignatureLength /// The message to be signed is of an invalid length case invalidMessageLengthForSigning /// The message to be encrypted is of an invalid length case invalidMessageLengthForEncryption /// The error thrown when Decryption fails case invalidDecryption } /// RSA Modulus public let n: BigUInteger /// RSA Public Exponent public let e: BigUInteger /// RSA Private Exponent public let d: BigUInteger? /// The size of the modulus, in bits public let keySize: Int /// The size of the modulus, in bytes (rounded up to the nearest full byte) public let keySizeBytes: Int /// The underlying primes used to generate the Private Exponent public let primes: (p: BigUInteger, q: BigUInteger)? /// Initialize with RSA parameters /// - Parameters: /// - n: The RSA Modulus /// - e: The RSA Public Exponent /// - d: The RSA Private Exponent (or nil if unknown, e.g. if only public key is known) public init(n: BigUInteger, e: BigUInteger, d: BigUInteger? = nil) { self.n = n self.e = e self.d = d self.primes = nil self.keySize = n.bitWidth self.keySizeBytes = n.byteWidth } /// Initialize with RSA parameters /// - Parameters: /// - n: The RSA Modulus /// - e: The RSA Public Exponent /// - d: The RSA Private Exponent (or nil if unknown, e.g. if only public key is known) public convenience init(n: Array, e: Array, d: Array? = nil) { if let d = d { self.init(n: BigUInteger(Data(n)), e: BigUInteger(Data(e)), d: BigUInteger(Data(d))) } else { self.init(n: BigUInteger(Data(n)), e: BigUInteger(Data(e))) } } /// Initialize with a generated key pair /// - Parameter keySize: The size of the modulus public convenience init(keySize: Int) throws { // Generate prime numbers let p = BigUInteger.generatePrime(keySize / 2) let q = BigUInteger.generatePrime(keySize / 2) // Calculate modulus let n = p * q // Calculate public and private exponent let e: BigUInteger = 65537 let phi = (p - 1) * (q - 1) guard let d = e.inverse(phi) else { throw RSA.Error.invalidInverseNotCoprimes } // Initialize try self.init(n: n, e: e, d: d, p: p, q: q) } /// Initialize with RSA parameters /// - Parameters: /// - n: The RSA Modulus /// - e: The RSA Public Exponent /// - d: The RSA Private Exponent /// - p: The 1st Prime used to generate the Private Exponent /// - q: The 2nd Prime used to generate the Private Exponent public init(n: BigUInteger, e: BigUInteger, d: BigUInteger, p: BigUInteger, q: BigUInteger) throws { // Ensure the supplied parameters are correct... // Calculate modulus guard n == p * q else { throw Error.invalidPrimes } // Calculate public and private exponent let phi = (p - 1) * (q - 1) guard d == e.inverse(phi) else { throw Error.invalidPrimes } // Regular initialization self.n = n self.e = e self.d = d self.primes = (p, q) self.keySize = n.bitWidth self.keySizeBytes = n.byteWidth } } // MARK: BigUInt Extension internal extension CS.BigUInt { /// The minimum number of bytes required to represent this integer in binary. var byteWidth: Int { let bytes = self.bitWidth / 8 return self.bitWidth % 8 == 0 ? bytes : bytes + 1 } } // MARK: DER Initializers (See #892) extension RSA { /// Decodes the provided data into a Public RSA Key /// /// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.1) /// ``` /// ========================= /// RSA PublicKey Structure /// ========================= /// /// RSAPublicKey ::= SEQUENCE { /// modulus INTEGER, -- n /// publicExponent INTEGER, -- e /// } /// ``` internal convenience init(publicDER der: Array) throws { let asn = try ASN1.Decoder.decode(data: Data(der)) // Enforce the above ASN Structure guard case .sequence(let params) = asn else { throw DER.Error.invalidDERFormat } guard params.count == 2 else { throw DER.Error.invalidDERFormat } guard case .integer(let modulus) = params[0] else { throw DER.Error.invalidDERFormat } guard case .integer(let publicExponent) = params[1] else { throw DER.Error.invalidDERFormat } self.init(n: BigUInteger(modulus), e: BigUInteger(publicExponent)) } /// Decodes the provided data into a Private RSA Key /// /// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.2) /// ``` /// ========================== /// RSA PrivateKey Structure /// ========================== /// /// RSAPrivateKey ::= SEQUENCE { /// version Version, /// modulus INTEGER, -- n /// publicExponent INTEGER, -- e /// privateExponent INTEGER, -- d /// prime1 INTEGER, -- p /// prime2 INTEGER, -- q /// exponent1 INTEGER, -- d mod (p-1) /// exponent2 INTEGER, -- d mod (q-1) /// coefficient INTEGER, -- (inverse of q) mod p /// } /// ``` internal convenience init(privateDER der: Array) throws { let asn = try ASN1.Decoder.decode(data: Data(der)) // Enforce the above ASN Structure (do we need to extract and verify the eponents and coefficients?) guard case .sequence(let params) = asn else { throw DER.Error.invalidDERFormat } guard params.count == 9 else { throw DER.Error.invalidDERFormat } guard case .integer(let version) = params[0] else { throw DER.Error.invalidDERFormat } guard case .integer(let modulus) = params[1] else { throw DER.Error.invalidDERFormat } guard case .integer(let publicExponent) = params[2] else { throw DER.Error.invalidDERFormat } guard case .integer(let privateExponent) = params[3] else { throw DER.Error.invalidDERFormat } guard case .integer(let prime1) = params[4] else { throw DER.Error.invalidDERFormat } guard case .integer(let prime2) = params[5] else { throw DER.Error.invalidDERFormat } guard case .integer(let exponent1) = params[6] else { throw DER.Error.invalidDERFormat } guard case .integer(let exponent2) = params[7] else { throw DER.Error.invalidDERFormat } guard case .integer(let coefficient) = params[8] else { throw DER.Error.invalidDERFormat } // We only support version 0x00 == RFC2313 at the moment // - TODO: Support multiple primes 0x01 version defined in [RFC3447](https://www.rfc-editor.org/rfc/rfc3447#appendix-A.1.2) guard version == Data(hex: "0x00") else { throw Error.unsupportedRSAVersion } // Calculate public and private exponent let phi = (BigUInteger(prime1) - 1) * (BigUInteger(prime2) - 1) guard let d = BigUInteger(publicExponent).inverse(phi) else { throw Error.invalidPrimes } guard BigUInteger(privateExponent) == d else { throw Error.invalidPrimes } // Ensure the provided coefficient is correct (derived from the primes) guard let calculatedCoefficient = BigUInteger(prime2).inverse(BigUInteger(prime1)) else { throw RSA.Error.unableToCalculateCoefficient } guard calculatedCoefficient == BigUInteger(coefficient) else { throw RSA.Error.invalidPrimes } // Ensure the provided exponents are correct as well guard (d % (BigUInteger(prime1) - 1)) == BigUInteger(exponent1) else { throw RSA.Error.invalidPrimes } guard (d % (BigUInteger(prime2) - 1)) == BigUInteger(exponent2) else { throw RSA.Error.invalidPrimes } // Proceed with regular initialization try self.init(n: BigUInteger(modulus), e: BigUInteger(publicExponent), d: BigUInteger(privateExponent), p: BigUInteger(prime1), q: BigUInteger(prime2)) } /// Attempts to instantiate an RSA Key when given the ASN1 DER encoded external representation of the Key /// /// An example of importing a SecKey RSA key (from Apple's `Security` framework) for use within CryptoSwift /// ``` /// /// Starting with a SecKey RSA Key /// let rsaSecKey:SecKey /// /// /// Copy the External Representation /// var externalRepError:Unmanaged? /// guard let externalRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else { /// /// Failed to copy external representation for RSA SecKey /// return /// } /// /// /// Instantiate the RSA Key from the raw external representation /// let rsaKey = try RSA(rawRepresentation: externalRep) /// /// /// You now have a CryptoSwift RSA Key /// // rsaKey.encrypt(...) /// // rsaKey.decrypt(...) /// // rsaKey.sign(...) /// // rsaKey.verify(...) /// ``` public convenience init(rawRepresentation raw: Data) throws { do { try self.init(privateDER: raw.byteArray) } catch { try self.init(publicDER: raw.byteArray) } } } // MARK: DER Exports (See #892) extension RSA { /// The DER representation of this public key /// /// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.1) /// ``` /// ========================= /// RSA PublicKey Structure /// ========================= /// /// RSAPublicKey ::= SEQUENCE { /// modulus INTEGER, -- n /// publicExponent INTEGER -- e /// } /// ``` func publicKeyDER() throws -> Array { let mod = self.n.serialize() let exp = self.e.serialize() let pubKeyAsnNode: ASN1.Node = .sequence(nodes: [ .integer(data: DER.i2ospData(x: mod.byteArray, size: self.keySizeBytes)), .integer(data: DER.i2ospData(x: exp.byteArray, size: exp.byteArray.count)) ]) return ASN1.Encoder.encode(pubKeyAsnNode) } /// The DER representation of this private key /// /// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.2) /// ``` /// ========================== /// RSA PrivateKey Structure /// ========================== /// /// RSAPrivateKey ::= SEQUENCE { /// version Version, /// modulus INTEGER, -- n /// publicExponent INTEGER, -- e /// privateExponent INTEGER, -- d /// prime1 INTEGER, -- p /// prime2 INTEGER, -- q /// exponent1 INTEGER, -- d mod (p-1) /// exponent2 INTEGER, -- d mod (q-1) /// coefficient INTEGER, -- (inverse of q) mod p /// } /// ``` func privateKeyDER() throws -> Array { // Make sure we have a private key guard let d = d else { throw RSA.Error.noPrivateKey } // Make sure we have access to our primes guard let primes = primes else { throw RSA.Error.noPrimes } // Make sure we can calculate our coefficient (inverse of q mod p) guard let coefficient = primes.q.inverse(primes.p) else { throw RSA.Error.unableToCalculateCoefficient } let paramWidth = self.keySizeBytes / 2 // Structure the data (according to RFC2313, version 0x00 RSA Private Key Syntax) let mod = self.n.serialize() let privateKeyAsnNode: ASN1.Node = .sequence(nodes: [ .integer(data: Data(hex: "0x00")), .integer(data: DER.i2ospData(x: mod.byteArray, size: self.keySizeBytes)), .integer(data: DER.i2ospData(x: self.e.serialize().byteArray, size: 3)), .integer(data: DER.i2ospData(x: d.serialize().byteArray, size: self.keySizeBytes)), .integer(data: DER.i2ospData(x: primes.p.serialize().byteArray, size: paramWidth)), .integer(data: DER.i2ospData(x: primes.q.serialize().byteArray, size: paramWidth)), .integer(data: DER.i2ospData(x: (d % (primes.p - 1)).serialize().byteArray, size: paramWidth)), .integer(data: DER.i2ospData(x: (d % (primes.q - 1)).serialize().byteArray, size: paramWidth)), .integer(data: DER.i2ospData(x: coefficient.serialize().byteArray, size: paramWidth)) ]) // Encode and return the data return ASN1.Encoder.encode(privateKeyAsnNode) } /// This method returns the DER encoding of the RSA Key. /// /// - Returns: The ASN1 DER Encoding of the Public or Private RSA Key /// - Note: If the RSA Key is a private key, the private key representation is returned /// - Note: If the RSA Key is a public key, the public key representation is returned /// - Note: If you'd like to only export the public DER of an RSA Key call the `publicKeyExternalRepresentation()` method /// - Note: This method returns the same data as Apple's `SecKeyCopyExternalRepresentation` method. /// /// An example of converting a CryptoSwift RSA key to a SecKey RSA key /// ``` /// /// Starting with a CryptoSwift RSA Key /// let rsaKey = try RSA(keySize: 1024) /// /// /// Define your Keys attributes /// let attributes: [String:Any] = [ /// kSecAttrKeyType as String: kSecAttrKeyTypeRSA, /// kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, // or kSecAttrKeyClassPublic /// kSecAttrKeySizeInBits as String: 1024, // The appropriate bits /// kSecAttrIsPermanent as String: false /// ] /// var error:Unmanaged? = nil /// guard let rsaSecKey = try SecKeyCreateWithData(rsaKey.externalRepresentation() as CFData, attributes as CFDictionary, &error) else { /// /// Error constructing SecKey from raw key data /// return /// } /// /// /// You now have an RSA SecKey for use with Apple's Security framework /// ``` /// /// An example of converting a SecKey RSA key to a CryptoSwift RSA key /// ``` /// /// Starting with a SecKey RSA Key /// let rsaSecKey:SecKey /// /// /// Copy External Representation /// var externalRepError:Unmanaged? /// guard let cfdata = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) else { /// /// Failed to copy external representation for RSA SecKey /// return /// } /// /// /// Instantiate the RSA Key from the raw external representation /// let rsaKey = try RSA(rawRepresentation: cfdata as Data) /// /// /// You now have a CryptoSwift RSA Key /// ``` /// public func externalRepresentation() throws -> Data { if self.d != nil { return try Data(self.privateKeyDER()) } else { return try Data(self.publicKeyDER()) } } public func publicKeyExternalRepresentation() throws -> Data { return try Data(self.publicKeyDER()) } } // MARK: CS.BigUInt extension extension BigUInteger { public static func generatePrime(_ width: Int) -> BigUInteger { // Note: Need to find a better way to generate prime numbers while true { var random = BigUInteger.randomInteger(withExactWidth: width) random |= BigUInteger(1) if random.isPrime() { return random } } } } // MARK: CustomStringConvertible Conformance extension RSA: CustomStringConvertible { public var description: String { if self.d != nil { return "CryptoSwift.RSA.PrivateKey<\(self.keySize)>" } else { return "CryptoSwift.RSA.PublicKey<\(self.keySize)>" } } } ================================================ FILE: Sources/CryptoSwift/Rabbit.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public final class Rabbit: BlockCipher { public enum Error: Swift.Error { case invalidKeyOrInitializationVector } /// Size of IV in bytes public static let ivSize = 64 / 8 /// Size of key in bytes public static let keySize = 128 / 8 /// Size of block in bytes public static let blockSize = 128 / 8 public var keySize: Int { self.key.count } /// Key private let key: Key /// IV (optional) private let iv: Array? /// State variables private var x = Array(repeating: 0, count: 8) /// Counter variables private var c = Array(repeating: 0, count: 8) /// Counter carry private var p7: UInt32 = 0 /// 'a' constants private var a: Array = [ 0x4d34d34d, 0xd34d34d3, 0x34d34d34, 0x4d34d34d, 0xd34d34d3, 0x34d34d34, 0x4d34d34d, 0xd34d34d3 ] // MARK: - Initializers public convenience init(key: Array) throws { try self.init(key: key, iv: nil) } public init(key: Array, iv: Array?) throws { self.key = Key(bytes: key) self.iv = iv guard key.count == Rabbit.keySize && (iv == nil || iv!.count == Rabbit.ivSize) else { throw Error.invalidKeyOrInitializationVector } } // MARK: - fileprivate func setup() { self.p7 = 0 // Key divided into 8 subkeys let k = Array(unsafeUninitializedCapacity: 8) { buf, count in for j in 0..<8 { buf[j] = UInt32(self.key[Rabbit.blockSize - (2 * j + 1)]) | (UInt32(self.key[Rabbit.blockSize - (2 * j + 2)]) << 8) } count = 8 } // Initialize state and counter variables from subkeys for j in 0..<8 { if j % 2 == 0 { self.x[j] = (k[(j + 1) % 8] << 16) | k[j] self.c[j] = (k[(j + 4) % 8] << 16) | k[(j + 5) % 8] } else { self.x[j] = (k[(j + 5) % 8] << 16) | k[(j + 4) % 8] self.c[j] = (k[j] << 16) | k[(j + 1) % 8] } } // Iterate system four times self.nextState() self.nextState() self.nextState() self.nextState() // Reinitialize counter variables for j in 0..<8 { self.c[j] = self.c[j] ^ self.x[(j + 4) % 8] } if let iv = iv { self.setupIV(iv) } } private func setupIV(_ iv: Array) { // 63...56 55...48 47...40 39...32 31...24 23...16 15...8 7...0 IV bits // 0 1 2 3 4 5 6 7 IV bytes in array let iv0 = UInt32(bytes: [iv[4], iv[5], iv[6], iv[7]]) let iv1 = UInt32(bytes: [iv[0], iv[1], iv[4], iv[5]]) let iv2 = UInt32(bytes: [iv[0], iv[1], iv[2], iv[3]]) let iv3 = UInt32(bytes: [iv[2], iv[3], iv[6], iv[7]]) // Modify the counter state as function of the IV c[0] = self.c[0] ^ iv0 self.c[1] = self.c[1] ^ iv1 self.c[2] = self.c[2] ^ iv2 self.c[3] = self.c[3] ^ iv3 self.c[4] = self.c[4] ^ iv0 self.c[5] = self.c[5] ^ iv1 self.c[6] = self.c[6] ^ iv2 self.c[7] = self.c[7] ^ iv3 // Iterate system four times self.nextState() self.nextState() self.nextState() self.nextState() } private func nextState() { // Before an iteration the counters are incremented var carry = self.p7 for j in 0..<8 { let prev = self.c[j] self.c[j] = prev &+ self.a[j] &+ carry carry = prev > self.c[j] ? 1 : 0 // detect overflow } self.p7 = carry // save last carry bit // Iteration of the system self.x = Array(unsafeUninitializedCapacity: 8) { newX, count in newX[0] = self.g(0) &+ rotateLeft(self.g(7), by: 16) &+ rotateLeft(self.g(6), by: 16) newX[1] = self.g(1) &+ rotateLeft(self.g(0), by: 8) &+ self.g(7) newX[2] = self.g(2) &+ rotateLeft(self.g(1), by: 16) &+ rotateLeft(self.g(0), by: 16) newX[3] = self.g(3) &+ rotateLeft(self.g(2), by: 8) &+ self.g(1) newX[4] = self.g(4) &+ rotateLeft(self.g(3), by: 16) &+ rotateLeft(self.g(2), by: 16) newX[5] = self.g(5) &+ rotateLeft(self.g(4), by: 8) &+ self.g(3) newX[6] = self.g(6) &+ rotateLeft(self.g(5), by: 16) &+ rotateLeft(self.g(4), by: 16) newX[7] = self.g(7) &+ rotateLeft(self.g(6), by: 8) &+ self.g(5) count = 8 } } private func g(_ j: Int) -> UInt32 { let sum = self.x[j] &+ self.c[j] let square = UInt64(sum) * UInt64(sum) return UInt32(truncatingIfNeeded: square ^ (square >> 32)) } fileprivate func nextOutput() -> Array { self.nextState() var output16 = Array(repeating: 0, count: Rabbit.blockSize / 2) output16[7] = UInt16(truncatingIfNeeded: self.x[0]) ^ UInt16(truncatingIfNeeded: self.x[5] >> 16) output16[6] = UInt16(truncatingIfNeeded: self.x[0] >> 16) ^ UInt16(truncatingIfNeeded: self.x[3]) output16[5] = UInt16(truncatingIfNeeded: self.x[2]) ^ UInt16(truncatingIfNeeded: self.x[7] >> 16) output16[4] = UInt16(truncatingIfNeeded: self.x[2] >> 16) ^ UInt16(truncatingIfNeeded: self.x[5]) output16[3] = UInt16(truncatingIfNeeded: self.x[4]) ^ UInt16(truncatingIfNeeded: self.x[1] >> 16) output16[2] = UInt16(truncatingIfNeeded: self.x[4] >> 16) ^ UInt16(truncatingIfNeeded: self.x[7]) output16[1] = UInt16(truncatingIfNeeded: self.x[6]) ^ UInt16(truncatingIfNeeded: self.x[3] >> 16) output16[0] = UInt16(truncatingIfNeeded: self.x[6] >> 16) ^ UInt16(truncatingIfNeeded: self.x[1]) var output8 = Array(repeating: 0, count: Rabbit.blockSize) for j in 0..> 8) output8[j * 2 + 1] = UInt8(truncatingIfNeeded: output16[j]) } return output8 } } // MARK: Cipher extension Rabbit: Cipher { public func encrypt(_ bytes: ArraySlice) throws -> Array { self.setup() return Array(unsafeUninitializedCapacity: bytes.count) { result, count in var output = self.nextOutput() var byteIdx = 0 var outputIdx = 0 while byteIdx < bytes.count { if outputIdx == Rabbit.blockSize { output = self.nextOutput() outputIdx = 0 } result[byteIdx] = bytes[byteIdx] ^ output[outputIdx] byteIdx += 1 outputIdx += 1 } count = bytes.count } } public func decrypt(_ bytes: ArraySlice) throws -> Array { try self.encrypt(bytes) } } ================================================ FILE: Sources/CryptoSwift/SHA1.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public final class SHA1: DigestType { @usableFromInline static let digestLength: Int = 20 // 160 / 8 @usableFromInline static let blockSize: Int = 64 @usableFromInline static let hashInitialValue: ContiguousArray = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0] @usableFromInline var accumulated = Array() @usableFromInline var processedBytesTotalCount: Int = 0 @usableFromInline var accumulatedHash: ContiguousArray = SHA1.hashInitialValue public init() { } @inlinable public func calculate(for bytes: Array) -> Array { do { return try update(withBytes: bytes.slice, isLast: true) } catch { return [] } } public func callAsFunction(_ bytes: Array) -> Array { calculate(for: bytes) } @usableFromInline func process(block chunk: ArraySlice, currentHash hh: inout ContiguousArray) { // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15, big-endian // Extend the sixteen 32-bit words into eighty 32-bit words: let M = UnsafeMutablePointer.allocate(capacity: 80) M.initialize(repeating: 0, count: 80) defer { M.deinitialize(count: 80) M.deallocate() } for x in 0..<80 { switch x { case 0...15: let start = chunk.startIndex.advanced(by: x * 4) // * MemoryLayout.size M[x] = UInt32(bytes: chunk, fromIndex: start) default: M[x] = rotateLeft(M[x - 3] ^ M[x - 8] ^ M[x - 14] ^ M[x - 16], by: 1) } } var A = hh[0] var B = hh[1] var C = hh[2] var D = hh[3] var E = hh[4] // Main loop for j in 0...79 { var f: UInt32 = 0 var k: UInt32 = 0 switch j { case 0...19: f = (B & C) | ((~B) & D) k = 0x5a827999 case 20...39: f = B ^ C ^ D k = 0x6ed9eba1 case 40...59: f = (B & C) | (B & D) | (C & D) k = 0x8f1bbcdc case 60...79: f = B ^ C ^ D k = 0xca62c1d6 default: break } let temp = rotateLeft(A, by: 5) &+ f &+ E &+ M[j] &+ k E = D D = C C = rotateLeft(B, by: 30) B = A A = temp } hh[0] = hh[0] &+ A hh[1] = hh[1] &+ B hh[2] = hh[2] &+ C hh[3] = hh[3] &+ D hh[4] = hh[4] &+ E } } extension SHA1: Updatable { @discardableResult @inlinable public func update(withBytes bytes: ArraySlice, isLast: Bool = false) throws -> Array { self.accumulated += bytes if isLast { let lengthInBits = (processedBytesTotalCount + self.accumulated.count) * 8 let lengthBytes = lengthInBits.bytes(totalBytes: 64 / 8) // A 64-bit representation of b // Step 1. Append padding bitPadding(to: &self.accumulated, blockSize: SHA1.blockSize, allowance: 64 / 8) // Step 2. Append Length a 64-bit representation of lengthInBits self.accumulated += lengthBytes } var processedBytes = 0 for chunk in self.accumulated.batched(by: SHA1.blockSize) { if isLast || (self.accumulated.count - processedBytes) >= SHA1.blockSize { self.process(block: chunk, currentHash: &self.accumulatedHash) processedBytes += chunk.count } } self.accumulated.removeFirst(processedBytes) self.processedBytesTotalCount += processedBytes // output current hash var result = Array(repeating: 0, count: SHA1.digestLength) var pos = 0 for idx in 0..> 24) & 0xff) result[pos + 1] = UInt8((h >> 16) & 0xff) result[pos + 2] = UInt8((h >> 8) & 0xff) result[pos + 3] = UInt8(h & 0xff) pos += 4 } // reset hash value for instance if isLast { self.accumulatedHash = SHA1.hashInitialValue } return result } } ================================================ FILE: Sources/CryptoSwift/SHA2.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // TODO: generic for process32/64 (UInt32/UInt64) // public final class SHA2: DigestType { @usableFromInline let variant: Variant @usableFromInline let size: Int @usableFromInline let blockSize: Int @usableFromInline let digestLength: Int private let k: Array @usableFromInline var accumulated = Array() @usableFromInline var processedBytesTotalCount: Int = 0 @usableFromInline var accumulatedHash32 = Array() @usableFromInline var accumulatedHash64 = Array() @frozen public enum Variant: RawRepresentable { case sha224, sha256, sha384, sha512 public var digestLength: Int { self.rawValue / 8 } public var blockSize: Int { switch self { case .sha224, .sha256: return 64 case .sha384, .sha512: return 128 } } public typealias RawValue = Int public var rawValue: RawValue { switch self { case .sha224: return 224 case .sha256: return 256 case .sha384: return 384 case .sha512: return 512 } } public init?(rawValue: RawValue) { switch rawValue { case 224: self = .sha224 case 256: self = .sha256 case 384: self = .sha384 case 512: self = .sha512 default: return nil } } @usableFromInline var h: Array { switch self { case .sha224: return [0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4] case .sha256: return [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19] case .sha384: return [0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4] case .sha512: return [0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179] } } @usableFromInline var finalLength: Int { switch self { case .sha224: return 7 case .sha384: return 6 default: return Int.max } } } public init(variant: SHA2.Variant) { self.variant = variant switch self.variant { case .sha224, .sha256: self.accumulatedHash32 = variant.h.map { UInt32($0) } // FIXME: UInt64 for process64 self.blockSize = variant.blockSize self.size = variant.rawValue self.digestLength = variant.digestLength self.k = [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 ] case .sha384, .sha512: self.accumulatedHash64 = variant.h self.blockSize = variant.blockSize self.size = variant.rawValue self.digestLength = variant.digestLength self.k = [ 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 ] } } @inlinable public func calculate(for bytes: Array) -> Array { do { return try update(withBytes: bytes.slice, isLast: true) } catch { return [] } } public func callAsFunction(_ bytes: Array) -> Array { calculate(for: bytes) } @usableFromInline func process64(block chunk: ArraySlice, currentHash hh: inout Array) { // break chunk into sixteen 64-bit words M[j], 0 ≤ j ≤ 15, big-endian // Extend the sixteen 64-bit words into eighty 64-bit words: let M = UnsafeMutablePointer.allocate(capacity: self.k.count) M.initialize(repeating: 0, count: self.k.count) defer { M.deinitialize(count: self.k.count) M.deallocate() } for x in 0...size M[x] = UInt64(bytes: chunk, fromIndex: start) default: let s0 = rotateRight(M[x - 15], by: 1) ^ rotateRight(M[x - 15], by: 8) ^ (M[x - 15] >> 7) let s1 = rotateRight(M[x - 2], by: 19) ^ rotateRight(M[x - 2], by: 61) ^ (M[x - 2] >> 6) M[x] = M[x - 16] &+ s0 &+ M[x - 7] &+ s1 } } var A = hh[0] var B = hh[1] var C = hh[2] var D = hh[3] var E = hh[4] var F = hh[5] var G = hh[6] var H = hh[7] // Main loop for j in 0.., currentHash hh: inout Array) { // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15, big-endian // Extend the sixteen 32-bit words into sixty-four 32-bit words: let M = UnsafeMutablePointer.allocate(capacity: self.k.count) M.initialize(repeating: 0, count: self.k.count) defer { M.deinitialize(count: self.k.count) M.deallocate() } for x in 0...size M[x] = UInt32(bytes: chunk, fromIndex: start) default: let s0 = rotateRight(M[x - 15], by: 7) ^ rotateRight(M[x - 15], by: 18) ^ (M[x - 15] >> 3) let s1 = rotateRight(M[x - 2], by: 17) ^ rotateRight(M[x - 2], by: 19) ^ (M[x - 2] >> 10) M[x] = M[x - 16] &+ s0 &+ M[x - 7] &+ s1 } } var A = hh[0] var B = hh[1] var C = hh[2] var D = hh[3] var E = hh[4] var F = hh[5] var G = hh[6] var H = hh[7] // Main loop for j in 0.., isLast: Bool = false) throws -> Array { self.accumulated += bytes if isLast { let lengthInBits = (processedBytesTotalCount + self.accumulated.count) * 8 let lengthBytes = lengthInBits.bytes(totalBytes: self.blockSize / 8) // A 64-bit/128-bit representation of b. blockSize fit by accident. // Step 1. Append padding bitPadding(to: &self.accumulated, blockSize: self.blockSize, allowance: self.blockSize / 8) // Step 2. Append Length a 64-bit representation of lengthInBits self.accumulated += lengthBytes } var processedBytes = 0 for chunk in self.accumulated.batched(by: self.blockSize) { if isLast || (self.accumulated.count - processedBytes) >= self.blockSize { switch self.variant { case .sha224, .sha256: self.process32(block: chunk, currentHash: &self.accumulatedHash32) case .sha384, .sha512: self.process64(block: chunk, currentHash: &self.accumulatedHash64) } processedBytes += chunk.count } } self.accumulated.removeFirst(processedBytes) self.processedBytesTotalCount += processedBytes // output current hash var result = Array(repeating: 0, count: variant.digestLength) switch self.variant { case .sha224, .sha256: var pos = 0 for idx in 0..> 24) & 0xff) result[pos + 1] = UInt8((h >> 16) & 0xff) result[pos + 2] = UInt8((h >> 8) & 0xff) result[pos + 3] = UInt8(h & 0xff) pos += 4 } case .sha384, .sha512: var pos = 0 for idx in 0..> 56) & 0xff) result[pos + 1] = UInt8((h >> 48) & 0xff) result[pos + 2] = UInt8((h >> 40) & 0xff) result[pos + 3] = UInt8((h >> 32) & 0xff) result[pos + 4] = UInt8((h >> 24) & 0xff) result[pos + 5] = UInt8((h >> 16) & 0xff) result[pos + 6] = UInt8((h >> 8) & 0xff) result[pos + 7] = UInt8(h & 0xff) pos += 8 } } // reset hash value for instance if isLast { switch self.variant { case .sha224, .sha256: self.accumulatedHash32 = self.variant.h.lazy.map { UInt32($0) } // FIXME: UInt64 for process64 case .sha384, .sha512: self.accumulatedHash64 = self.variant.h } } return result } } ================================================ FILE: Sources/CryptoSwift/SHA3.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf // http://keccak.noekeon.org/specs_summary.html // #if canImport(Darwin) import Darwin #elseif canImport(Android) import Android #elseif canImport(Glibc) import Glibc #elseif canImport(Musl) import Musl #elseif canImport(ucrt) import ucrt #endif public final class SHA3: DigestType { let round_constants: Array = [ 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 ] public let blockSize: Int public let digestLength: Int public let markByte: UInt8 @usableFromInline var accumulated = Array() @usableFromInline var accumulatedHash: Array public enum Variant { case sha224, sha256, sha384, sha512, keccak224, keccak256, keccak384, keccak512 var digestLength: Int { 100 - (self.blockSize / 2) } var blockSize: Int { (1600 - self.outputLength * 2) / 8 } var markByte: UInt8 { switch self { case .sha224, .sha256, .sha384, .sha512: return 0x06 // 0x1F for SHAKE case .keccak224, .keccak256, .keccak384, .keccak512: return 0x01 } } public var outputLength: Int { switch self { case .sha224, .keccak224: return 224 case .sha256, .keccak256: return 256 case .sha384, .keccak384: return 384 case .sha512, .keccak512: return 512 } } } public init(variant: SHA3.Variant) { self.blockSize = variant.blockSize self.digestLength = variant.digestLength self.markByte = variant.markByte self.accumulatedHash = Array(repeating: 0, count: self.digestLength) } @inlinable public func calculate(for bytes: Array) -> Array { do { return try update(withBytes: bytes.slice, isLast: true) } catch { return [] } } public func callAsFunction(_ bytes: Array) -> Array { calculate(for: bytes) } /// 1. For all pairs (x,z) such that 0≤x<5 and 0≤z) { let c = UnsafeMutablePointer.allocate(capacity: 5) c.initialize(repeating: 0, count: 5) defer { c.deinitialize(count: 5) c.deallocate() } let d = UnsafeMutablePointer.allocate(capacity: 5) d.initialize(repeating: 0, count: 5) defer { d.deinitialize(count: 5) d.deallocate() } for i in 0..<5 { c[i] = a[i] ^ a[i &+ 5] ^ a[i &+ 10] ^ a[i &+ 15] ^ a[i &+ 20] } d[0] = rotateLeft(c[1], by: 1) ^ c[4] d[1] = rotateLeft(c[2], by: 1) ^ c[0] d[2] = rotateLeft(c[3], by: 1) ^ c[1] d[3] = rotateLeft(c[4], by: 1) ^ c[2] d[4] = rotateLeft(c[0], by: 1) ^ c[3] for i in 0..<5 { a[i] ^= d[i] a[i &+ 5] ^= d[i] a[i &+ 10] ^= d[i] a[i &+ 15] ^= d[i] a[i &+ 20] ^= d[i] } } /// A′[x, y, z]=A[(x &+ 3y) mod 5, x, z] private func π(_ a: inout Array) { let a1 = a[1] a[1] = a[6] a[6] = a[9] a[9] = a[22] a[22] = a[14] a[14] = a[20] a[20] = a[2] a[2] = a[12] a[12] = a[13] a[13] = a[19] a[19] = a[23] a[23] = a[15] a[15] = a[4] a[4] = a[24] a[24] = a[21] a[21] = a[8] a[8] = a[16] a[16] = a[5] a[5] = a[3] a[3] = a[18] a[18] = a[17] a[17] = a[11] a[11] = a[7] a[7] = a[10] a[10] = a1 } /// For all triples (x, y, z) such that 0≤x<5, 0≤y<5, and 0≤z) { for i in stride(from: 0, to: 25, by: 5) { let a0 = a[0 &+ i] let a1 = a[1 &+ i] a[0 &+ i] ^= ~a1 & a[2 &+ i] a[1 &+ i] ^= ~a[2 &+ i] & a[3 &+ i] a[2 &+ i] ^= ~a[3 &+ i] & a[4 &+ i] a[3 &+ i] ^= ~a[4 &+ i] & a0 a[4 &+ i] ^= ~a0 & a1 } } private func ι(_ a: inout Array, round: Int) { a[0] ^= self.round_constants[round] } @usableFromInline func process(block chunk: ArraySlice, currentHash hh: inout Array) { // expand hh[0] ^= chunk[0].littleEndian hh[1] ^= chunk[1].littleEndian hh[2] ^= chunk[2].littleEndian hh[3] ^= chunk[3].littleEndian hh[4] ^= chunk[4].littleEndian hh[5] ^= chunk[5].littleEndian hh[6] ^= chunk[6].littleEndian hh[7] ^= chunk[7].littleEndian hh[8] ^= chunk[8].littleEndian if self.blockSize > 72 { // 72 / 8, sha-512 hh[9] ^= chunk[9].littleEndian hh[10] ^= chunk[10].littleEndian hh[11] ^= chunk[11].littleEndian hh[12] ^= chunk[12].littleEndian if self.blockSize > 104 { // 104 / 8, sha-384 hh[13] ^= chunk[13].littleEndian hh[14] ^= chunk[14].littleEndian hh[15] ^= chunk[15].littleEndian hh[16] ^= chunk[16].littleEndian if self.blockSize > 136 { // 136 / 8, sha-256 hh[17] ^= chunk[17].littleEndian // FULL_SHA3_FAMILY_SUPPORT if self.blockSize > 144 { // 144 / 8, sha-224 hh[18] ^= chunk[18].littleEndian hh[19] ^= chunk[19].littleEndian hh[20] ^= chunk[20].littleEndian hh[21] ^= chunk[21].littleEndian hh[22] ^= chunk[22].littleEndian hh[23] ^= chunk[23].littleEndian hh[24] ^= chunk[24].littleEndian } } } } // Keccak-f for round in 0..<24 { self.θ(&hh) hh[1] = rotateLeft(hh[1], by: 1) hh[2] = rotateLeft(hh[2], by: 62) hh[3] = rotateLeft(hh[3], by: 28) hh[4] = rotateLeft(hh[4], by: 27) hh[5] = rotateLeft(hh[5], by: 36) hh[6] = rotateLeft(hh[6], by: 44) hh[7] = rotateLeft(hh[7], by: 6) hh[8] = rotateLeft(hh[8], by: 55) hh[9] = rotateLeft(hh[9], by: 20) hh[10] = rotateLeft(hh[10], by: 3) hh[11] = rotateLeft(hh[11], by: 10) hh[12] = rotateLeft(hh[12], by: 43) hh[13] = rotateLeft(hh[13], by: 25) hh[14] = rotateLeft(hh[14], by: 39) hh[15] = rotateLeft(hh[15], by: 41) hh[16] = rotateLeft(hh[16], by: 45) hh[17] = rotateLeft(hh[17], by: 15) hh[18] = rotateLeft(hh[18], by: 21) hh[19] = rotateLeft(hh[19], by: 8) hh[20] = rotateLeft(hh[20], by: 18) hh[21] = rotateLeft(hh[21], by: 2) hh[22] = rotateLeft(hh[22], by: 61) hh[23] = rotateLeft(hh[23], by: 56) hh[24] = rotateLeft(hh[24], by: 14) self.π(&hh) self.χ(&hh) self.ι(&hh, round: round) } } } extension SHA3: Updatable { @inlinable public func update(withBytes bytes: ArraySlice, isLast: Bool = false) throws -> Array { self.accumulated += bytes if isLast { // Add padding let markByteIndex = self.accumulated.count // We need to always pad the input. Even if the input is a multiple of blockSize. let r = self.blockSize * 8 let q = (r / 8) - (accumulated.count % (r / 8)) self.accumulated += Array(repeating: 0, count: q) self.accumulated[markByteIndex] |= self.markByte self.accumulated[self.accumulated.count - 1] |= 0x80 } var processedBytes = 0 for chunk in self.accumulated.batched(by: self.blockSize) { if isLast || (self.accumulated.count - processedBytes) >= self.blockSize { self.process(block: chunk.toUInt64Array().slice, currentHash: &self.accumulatedHash) processedBytes += chunk.count } } self.accumulated.removeFirst(processedBytes) // TODO: verify performance, reduce vs for..in let result = self.accumulatedHash.reduce(into: Array()) { (result, value) in result += value.bigEndian.bytes() } // reset hash value for instance if isLast { self.accumulatedHash = Array(repeating: 0, count: self.digestLength) } return Array(result[0.. // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // // https://tools.ietf.org/html/rfc7914 // /// Implementation of the scrypt key derivation function. public final class Scrypt { enum Error: Swift.Error { case nIsTooLarge case rIsTooLarge case nMustBeAPowerOf2GreaterThan1 case invalidInput } /// Configuration parameters. private let salt: SecureBytes private let password: SecureBytes private let blocksize: Int // 128 * r private let salsaBlock = UnsafeMutableRawPointer.allocate(byteCount: 64, alignment: 64) private let dkLen: Int private let N: Int private let r: Int private let p: Int /// - parameters: /// - password: password /// - salt: salt /// - dkLen: output length /// - N: determines extra memory used /// - r: determines a block size /// - p: determines parallelicity degree public init(password: Array, salt: Array, dkLen: Int, N: Int, r: Int, p: Int) throws { precondition(dkLen > 0) precondition(N > 0) precondition(r > 0) precondition(p > 0) guard !(N < 2 || (N & (N - 1)) != 0) else { throw Error.nMustBeAPowerOf2GreaterThan1 } guard N <= .max / 128 / r else { throw Error.nIsTooLarge } guard r <= .max / 128 / p else { throw Error.rIsTooLarge } guard !salt.isEmpty else { throw Error.invalidInput } self.blocksize = 128 * r self.N = N self.r = r self.p = p self.password = SecureBytes(bytes: password) self.salt = SecureBytes(bytes: salt) self.dkLen = dkLen } deinit { salsaBlock.deallocate() } /// Runs the key derivation function with a specific password. public func calculate() throws -> [UInt8] { // Allocate memory (as bytes for now) for further use in mixing steps let B = UnsafeMutableRawPointer.allocate(byteCount: 128 * self.r * self.p, alignment: 64) let XY = UnsafeMutableRawPointer.allocate(byteCount: 256 * self.r + 64, alignment: 64) let V = UnsafeMutableRawPointer.allocate(byteCount: 128 * self.r * self.N, alignment: 64) // Deallocate memory when done defer { B.deallocate() XY.deallocate() V.deallocate() } /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ // Expand the initial key let barray = try PKCS5.PBKDF2(password: Array(self.password), salt: Array(self.salt), iterations: 1, keyLength: self.p * 128 * self.r, variant: .sha2(.sha256)).calculate() barray.withUnsafeBytes { bufferPointer in guard let baseAddress = bufferPointer.baseAddress else { return } B.copyMemory(from: baseAddress, byteCount: barray.count) } /* 2: for i = 0 to p - 1 do */ // do the mixing for i in 0 ..< self.p { /* 3: B_i <-- MF(B_i, N) */ smix(B + i * 128 * self.r, V.assumingMemoryBound(to: UInt32.self), XY.assumingMemoryBound(to: UInt32.self)) } /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ let pointer = B.assumingMemoryBound(to: UInt8.self) let bufferPointer = UnsafeBufferPointer(start: pointer, count: p * 128 * self.r) let block = [UInt8](bufferPointer) return try PKCS5.PBKDF2(password: Array(self.password), salt: block, iterations: 1, keyLength: self.dkLen, variant: .sha2(.sha256)).calculate() } public func callAsFunction() throws -> Array { try calculate() } } private extension Scrypt { /// Computes `B = SMix_r(B, N)`. /// /// The input `block` must be `128*r` bytes in length; the temporary storage `v` must be `128*r*n` bytes in length; /// the temporary storage `xy` must be `256*r + 64` bytes in length. The arrays `block`, `v`, and `xy` must be /// aligned to a multiple of 64 bytes. @inline(__always) func smix(_ block: UnsafeMutableRawPointer, _ v: UnsafeMutablePointer, _ xy: UnsafeMutablePointer) { let X = xy let Y = xy + 32 * self.r let Z = xy + 64 * self.r /* 1: X <-- B */ let typedBlock = block.assumingMemoryBound(to: UInt32.self) #if compiler(>=5.8) X.update(from: typedBlock, count: 32 * self.r) #else X.assign(from: typedBlock, count: 32 * self.r) #endif /* 2: for i = 0 to N - 1 do */ for i in stride(from: 0, to: self.N, by: 2) { /* 3: V_i <-- X */ UnsafeMutableRawPointer(v + i * (32 * self.r)).copyMemory(from: X, byteCount: 128 * self.r) /* 4: X <-- H(X) */ self.blockMixSalsa8(X, Y, Z) /* 3: V_i <-- X */ UnsafeMutableRawPointer(v + (i + 1) * (32 * self.r)).copyMemory(from: Y, byteCount: 128 * self.r) /* 4: X <-- H(X) */ self.blockMixSalsa8(Y, X, Z) } /* 6: for i = 0 to N - 1 do */ for _ in stride(from: 0, to: self.N, by: 2) { /* 7: j <-- Integerify (X) mod N where Integerify (B[0] ... B[2 * r - 1]) is defined as the result of interpreting B[2 * r - 1] as a little-endian integer. */ var j = Int(integerify(X) & UInt64(self.N - 1)) /* 8: X <-- H(X \xor V_j) */ self.blockXor(X, v + j * 32 * self.r, 128 * self.r) self.blockMixSalsa8(X, Y, Z) /* 7: j <-- Integerify(X) mod N */ j = Int(self.integerify(Y) & UInt64(self.N - 1)) /* 8: X <-- H(X \xor V_j) */ self.blockXor(Y, v + j * 32 * self.r, 128 * self.r) self.blockMixSalsa8(Y, X, Z) } /* 10: B' <-- X */ for k in 0 ..< 32 * self.r { UnsafeMutableRawPointer(block + 4 * k).storeBytes(of: X[k], as: UInt32.self) } } /// Returns the result of parsing `B_{2r-1}` as a little-endian integer. @inline(__always) func integerify(_ block: UnsafeRawPointer) -> UInt64 { let bi = block + (2 * self.r - 1) * 64 return bi.load(as: UInt64.self).littleEndian } /// Compute `bout = BlockMix_{salsa20/8, r}(bin)`. /// /// The input `bin` must be `128*r` bytes in length; the output `bout` must also be the same size. The temporary /// space `x` must be 64 bytes. @inline(__always) func blockMixSalsa8(_ bin: UnsafePointer, _ bout: UnsafeMutablePointer, _ x: UnsafeMutablePointer) { /* 1: X <-- B_{2r - 1} */ UnsafeMutableRawPointer(x).copyMemory(from: bin + (2 * self.r - 1) * 16, byteCount: 64) /* 2: for i = 0 to 2r - 1 do */ for i in stride(from: 0, to: 2 * self.r, by: 2) { /* 3: X <-- H(X \xor B_i) */ self.blockXor(x, bin + i * 16, 64) self.salsa20_8_typed(x) /* 4: Y_i <-- X */ /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ UnsafeMutableRawPointer(bout + i * 8).copyMemory(from: x, byteCount: 64) /* 3: X <-- H(X \xor B_i) */ self.blockXor(x, bin + i * 16 + 16, 64) self.salsa20_8_typed(x) /* 4: Y_i <-- X */ /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ UnsafeMutableRawPointer(bout + i * 8 + self.r * 16).copyMemory(from: x, byteCount: 64) } } @inline(__always) func salsa20_8_typed(_ block: UnsafeMutablePointer) { self.salsaBlock.copyMemory(from: UnsafeRawPointer(block), byteCount: 64) let salsaBlockTyped = self.salsaBlock.assumingMemoryBound(to: UInt32.self) for _ in stride(from: 0, to: 8, by: 2) { salsaBlockTyped[4] ^= rotateLeft(salsaBlockTyped[0] &+ salsaBlockTyped[12], by: 7) salsaBlockTyped[8] ^= rotateLeft(salsaBlockTyped[4] &+ salsaBlockTyped[0], by: 9) salsaBlockTyped[12] ^= rotateLeft(salsaBlockTyped[8] &+ salsaBlockTyped[4], by: 13) salsaBlockTyped[0] ^= rotateLeft(salsaBlockTyped[12] &+ salsaBlockTyped[8], by: 18) salsaBlockTyped[9] ^= rotateLeft(salsaBlockTyped[5] &+ salsaBlockTyped[1], by: 7) salsaBlockTyped[13] ^= rotateLeft(salsaBlockTyped[9] &+ salsaBlockTyped[5], by: 9) salsaBlockTyped[1] ^= rotateLeft(salsaBlockTyped[13] &+ salsaBlockTyped[9], by: 13) salsaBlockTyped[5] ^= rotateLeft(salsaBlockTyped[1] &+ salsaBlockTyped[13], by: 18) salsaBlockTyped[14] ^= rotateLeft(salsaBlockTyped[10] &+ salsaBlockTyped[6], by: 7) salsaBlockTyped[2] ^= rotateLeft(salsaBlockTyped[14] &+ salsaBlockTyped[10], by: 9) salsaBlockTyped[6] ^= rotateLeft(salsaBlockTyped[2] &+ salsaBlockTyped[14], by: 13) salsaBlockTyped[10] ^= rotateLeft(salsaBlockTyped[6] &+ salsaBlockTyped[2], by: 18) salsaBlockTyped[3] ^= rotateLeft(salsaBlockTyped[15] &+ salsaBlockTyped[11], by: 7) salsaBlockTyped[7] ^= rotateLeft(salsaBlockTyped[3] &+ salsaBlockTyped[15], by: 9) salsaBlockTyped[11] ^= rotateLeft(salsaBlockTyped[7] &+ salsaBlockTyped[3], by: 13) salsaBlockTyped[15] ^= rotateLeft(salsaBlockTyped[11] &+ salsaBlockTyped[7], by: 18) salsaBlockTyped[1] ^= rotateLeft(salsaBlockTyped[0] &+ salsaBlockTyped[3], by: 7) salsaBlockTyped[2] ^= rotateLeft(salsaBlockTyped[1] &+ salsaBlockTyped[0], by: 9) salsaBlockTyped[3] ^= rotateLeft(salsaBlockTyped[2] &+ salsaBlockTyped[1], by: 13) salsaBlockTyped[0] ^= rotateLeft(salsaBlockTyped[3] &+ salsaBlockTyped[2], by: 18) salsaBlockTyped[6] ^= rotateLeft(salsaBlockTyped[5] &+ salsaBlockTyped[4], by: 7) salsaBlockTyped[7] ^= rotateLeft(salsaBlockTyped[6] &+ salsaBlockTyped[5], by: 9) salsaBlockTyped[4] ^= rotateLeft(salsaBlockTyped[7] &+ salsaBlockTyped[6], by: 13) salsaBlockTyped[5] ^= rotateLeft(salsaBlockTyped[4] &+ salsaBlockTyped[7], by: 18) salsaBlockTyped[11] ^= rotateLeft(salsaBlockTyped[10] &+ salsaBlockTyped[9], by: 7) salsaBlockTyped[8] ^= rotateLeft(salsaBlockTyped[11] &+ salsaBlockTyped[10], by: 9) salsaBlockTyped[9] ^= rotateLeft(salsaBlockTyped[8] &+ salsaBlockTyped[11], by: 13) salsaBlockTyped[10] ^= rotateLeft(salsaBlockTyped[9] &+ salsaBlockTyped[8], by: 18) salsaBlockTyped[12] ^= rotateLeft(salsaBlockTyped[15] &+ salsaBlockTyped[14], by: 7) salsaBlockTyped[13] ^= rotateLeft(salsaBlockTyped[12] &+ salsaBlockTyped[15], by: 9) salsaBlockTyped[14] ^= rotateLeft(salsaBlockTyped[13] &+ salsaBlockTyped[12], by: 13) salsaBlockTyped[15] ^= rotateLeft(salsaBlockTyped[14] &+ salsaBlockTyped[13], by: 18) } for i in 0 ..< 16 { block[i] = block[i] &+ salsaBlockTyped[i] } } @inline(__always) func blockXor(_ dest: UnsafeMutableRawPointer, _ src: UnsafeRawPointer, _ len: Int) { let D = dest.assumingMemoryBound(to: UInt64.self) let S = src.assumingMemoryBound(to: UInt64.self) let L = len / MemoryLayout.size for i in 0 ..< L { D[i] ^= S[i] } } } ================================================ FILE: Sources/CryptoSwift/SecureBytes.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // #if canImport(Darwin) import Darwin #elseif canImport(Android) import Android #elseif canImport(Glibc) import Glibc #elseif canImport(Musl) import Musl #elseif canImport(WinSDK) import WinSDK #endif typealias Key = SecureBytes /// Keeps bytes in memory. Because this is class, bytes are not copied /// and memory area is locked as long as referenced, then unlocked on deinit final class SecureBytes { private let bytes: Array let count: Int init(bytes: Array) { self.bytes = bytes self.count = bytes.count self.bytes.withUnsafeBufferPointer { (pointer) -> Void in guard let baseAddress = pointer.baseAddress else { return } #if os(Windows) VirtualLock(UnsafeMutableRawPointer(mutating: baseAddress), SIZE_T(pointer.count)) #elseif os(WASI) // not supported on WASI #elseif os(Android) mlock(baseAddress, pointer.count) #else mlock(baseAddress, pointer.count) #endif } } deinit { self.bytes.withUnsafeBufferPointer { (pointer) -> Void in guard let baseAddress = pointer.baseAddress else { return } #if os(Windows) VirtualUnlock(UnsafeMutableRawPointer(mutating: baseAddress), SIZE_T(pointer.count)) #elseif os(WASI) // not supported on WASI #elseif os(Android) munlock(baseAddress, pointer.count) #else munlock(baseAddress, pointer.count) #endif } } } extension SecureBytes: Collection { typealias Index = Int var endIndex: Int { self.bytes.endIndex } var startIndex: Int { self.bytes.startIndex } subscript(position: Index) -> UInt8 { self.bytes[position] } subscript(bounds: Range) -> ArraySlice { self.bytes[bounds] } func formIndex(after i: inout Int) { self.bytes.formIndex(after: &i) } func index(after i: Int) -> Int { self.bytes.index(after: i) } } extension SecureBytes: ExpressibleByArrayLiteral { public convenience init(arrayLiteral elements: UInt8...) { self.init(bytes: elements) } } ================================================ FILE: Sources/CryptoSwift/Signature.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // public enum SignatureError: Error { case sign case verify } public protocol Signature: AnyObject { var keySize: Int { get } /// Sign the given bytes at once /// /// - parameter bytes: Plaintext data to be signed /// - returns: The signed data func sign(_ bytes: ArraySlice) throws -> Array /// Sign the given bytes at once /// /// - parameter bytes: Plaintext data to be signed /// - returns: The signed data func sign(_ bytes: Array) throws -> Array /// Verify the given bytes against the expected data /// /// - parameter signature: Signature data /// - parameter expectedData: The original data that you expected to be signed /// - returns: `True` when the signature is valid for the expected data, `False` otherwise. func verify(signature: ArraySlice, for expectedData: ArraySlice) throws -> Bool /// Verify the given bytes against the expected data /// /// - parameter signature: Signature data /// - parameter expectedData: The original data that you expected to be signed /// - returns: `True` when the signature is valid for the expected data, `False` otherwise. func verify(signature: Array, for expectedData: Array) throws -> Bool } extension Signature { /// Sign the given bytes at once /// /// - parameter bytes: Plaintext data to be signed /// - returns: The signed data public func sign(_ bytes: Array) throws -> Array { try self.sign(bytes.slice) } /// Verify the given bytes against the expected data /// /// - parameter signature: Signature data /// - parameter expectedData: The original data that you expected to be signed /// - returns: `True` when the signature is valid for the expected data, `False` otherwise. public func verify(signature: Array, for expectedData: Array) throws -> Bool { try self.verify(signature: signature.slice, for: expectedData.slice) } } ================================================ FILE: Sources/CryptoSwift/StreamDecryptor.swift ================================================ // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // @usableFromInline final class StreamDecryptor: Cryptor, Updatable { @usableFromInline enum Error: Swift.Error { case unsupported } @usableFromInline internal let blockSize: Int @usableFromInline internal var worker: CipherModeWorker @usableFromInline internal let padding: Padding @usableFromInline internal var accumulated = Array() @usableFromInline internal var lastBlockRemainder = 0 @usableFromInline init(blockSize: Int, padding: Padding, _ worker: CipherModeWorker) throws { self.blockSize = blockSize self.padding = padding self.worker = worker } // MARK: Updatable @inlinable public func update(withBytes bytes: ArraySlice, isLast: Bool) throws -> Array { self.accumulated += bytes let toProcess = self.accumulated.prefix(max(self.accumulated.count - self.worker.additionalBufferSize, 0)) if var finalizingWorker = worker as? FinalizingDecryptModeWorker, isLast == true { // will truncate suffix if needed try finalizingWorker.willDecryptLast(bytes: self.accumulated.slice) } var processedBytesCount = 0 var plaintext = Array(reserveCapacity: bytes.count + self.worker.additionalBufferSize) for chunk in toProcess.batched(by: self.blockSize) { plaintext += self.worker.decrypt(block: chunk) processedBytesCount += chunk.count } if var finalizingWorker = worker as? FinalizingDecryptModeWorker, isLast == true { plaintext = Array(try finalizingWorker.didDecryptLast(bytes: plaintext.slice)) } // omit unnecessary calculation if not needed if self.padding != .noPadding { self.lastBlockRemainder = plaintext.count.quotientAndRemainder(dividingBy: self.blockSize).remainder } if isLast { // CTR doesn't need padding. Really. Add padding to the last block if really want. but... don't. plaintext = self.padding.remove(from: plaintext, blockSize: self.blockSize - self.lastBlockRemainder) } self.accumulated.removeFirst(processedBytesCount) // super-slow if var finalizingWorker = worker as? FinalizingDecryptModeWorker, isLast == true { plaintext = Array(try finalizingWorker.finalize(decrypt: plaintext.slice)) } return plaintext } @inlinable public func seek(to position: Int) throws { guard var worker = self.worker as? SeekableModeWorker else { throw Error.unsupported } try worker.seek(to: position) self.worker = worker } } ================================================ FILE: Sources/CryptoSwift/StreamEncryptor.swift ================================================ // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // @usableFromInline final class StreamEncryptor: Cryptor, Updatable { @usableFromInline enum Error: Swift.Error { case unsupported } @usableFromInline internal let blockSize: Int @usableFromInline internal var worker: CipherModeWorker @usableFromInline internal let padding: Padding @usableFromInline internal var lastBlockRemainder = 0 @usableFromInline init(blockSize: Int, padding: Padding, _ worker: CipherModeWorker) throws { self.blockSize = blockSize self.padding = padding self.worker = worker } // MARK: Updatable @inlinable public func update(withBytes bytes: ArraySlice, isLast: Bool) throws -> Array { var accumulated = Array(bytes) if isLast { // CTR doesn't need padding. Really. Add padding to the last block if really want. but... don't. accumulated = self.padding.add(to: accumulated, blockSize: self.blockSize - self.lastBlockRemainder) } var encrypted = Array(reserveCapacity: bytes.count) for chunk in accumulated.batched(by: self.blockSize) { encrypted += self.worker.encrypt(block: chunk) } // omit unnecessary calculation if not needed if self.padding != .noPadding { self.lastBlockRemainder = encrypted.count.quotientAndRemainder(dividingBy: self.blockSize).remainder } if var finalizingWorker = worker as? FinalizingEncryptModeWorker, isLast == true { encrypted = Array(try finalizingWorker.finalize(encrypt: encrypted.slice)) } return encrypted } @usableFromInline func seek(to: Int) throws { throw Error.unsupported } } ================================================ FILE: Sources/CryptoSwift/String+Extension.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation /** String extension */ extension String { @inlinable public var bytes: Array { data(using: String.Encoding.utf8, allowLossyConversion: true)?.byteArray ?? Array(utf8) } @inlinable public func md5() -> String { self.bytes.md5().toHexString() } @inlinable public func sha1() -> String { self.bytes.sha1().toHexString() } @inlinable public func sha224() -> String { self.bytes.sha224().toHexString() } @inlinable public func sha256() -> String { self.bytes.sha256().toHexString() } @inlinable public func sha384() -> String { self.bytes.sha384().toHexString() } @inlinable public func sha512() -> String { self.bytes.sha512().toHexString() } @inlinable public func sha3(_ variant: SHA3.Variant) -> String { self.bytes.sha3(variant).toHexString() } @inlinable public func crc32(seed: UInt32? = nil, reflect: Bool = true) -> String { self.bytes.crc32(seed: seed, reflect: reflect).bytes().toHexString() } @inlinable public func crc32c(seed: UInt32? = nil, reflect: Bool = true) -> String { self.bytes.crc32c(seed: seed, reflect: reflect).bytes().toHexString() } @inlinable public func crc16(seed: UInt16? = nil) -> String { self.bytes.crc16(seed: seed).bytes().toHexString() } /// - parameter cipher: Instance of `Cipher` /// - returns: hex string of bytes @inlinable public func encrypt(cipher: Cipher) throws -> String { try self.bytes.encrypt(cipher: cipher).toHexString() } /// - parameter cipher: Instance of `Cipher` /// - returns: base64 encoded string of encrypted bytes @inlinable public func encryptToBase64(cipher: Cipher) throws -> String { try self.bytes.encrypt(cipher: cipher).toBase64() } // decrypt() does not make sense for String /// - parameter authenticator: Instance of `Authenticator` /// - returns: hex string of string @inlinable public func authenticate(with authenticator: A) throws -> String { try self.bytes.authenticate(with: authenticator).toHexString() } } ================================================ FILE: Sources/CryptoSwift/UInt128.swift ================================================ // // UInt128.swift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation struct UInt128: Equatable, ExpressibleByIntegerLiteral { let i: (a: UInt64, b: UInt64) typealias IntegerLiteralType = UInt64 init(integerLiteral value: IntegerLiteralType) { self = UInt128(value) } init(_ raw: Array) { precondition(raw.count >= 16, "UInt128 requires at least 16 bytes") let a = UInt64(raw[0]) << 56 | UInt64(raw[1]) << 48 | UInt64(raw[2]) << 40 | UInt64(raw[3]) << 32 | UInt64(raw[4]) << 24 | UInt64(raw[5]) << 16 | UInt64(raw[6]) << 8 | UInt64(raw[7]) let b = UInt64(raw[8]) << 56 | UInt64(raw[9]) << 48 | UInt64(raw[10]) << 40 | UInt64(raw[11]) << 32 | UInt64(raw[12]) << 24 | UInt64(raw[13]) << 16 | UInt64(raw[14]) << 8 | UInt64(raw[15]) self.init((a, b)) } init(_ raw: ArraySlice) { self.init(Array(raw)) } init(_ i: (a: UInt64, b: UInt64)) { self.i = i } init(a: UInt64, b: UInt64) { self.init((a, b)) } init(_ b: UInt64) { self.init((0, b)) } // Bytes var bytes: Array { var at = self.i.a.bigEndian var bt = self.i.b.bigEndian let ar = Data(bytes: &at, count: MemoryLayout.size(ofValue: at)) let br = Data(bytes: &bt, count: MemoryLayout.size(ofValue: bt)) var result = Data() result.append(ar) result.append(br) return result.byteArray } static func ^ (n1: UInt128, n2: UInt128) -> UInt128 { UInt128((n1.i.a ^ n2.i.a, n1.i.b ^ n2.i.b)) } static func & (n1: UInt128, n2: UInt128) -> UInt128 { UInt128((n1.i.a & n2.i.a, n1.i.b & n2.i.b)) } static func >> (value: UInt128, by: Int) -> UInt128 { var result = value for _ in 0..> 1 let b = result.i.b >> 1 + ((result.i.a & 1) << 63) result = UInt128((a, b)) } return result } // Equatable. static func == (lhs: UInt128, rhs: UInt128) -> Bool { lhs.i == rhs.i } static func != (lhs: UInt128, rhs: UInt128) -> Bool { !(lhs == rhs) } } ================================================ FILE: Sources/CryptoSwift/UInt16+Extension.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // /** array of bytes */ extension UInt16 { @_specialize(where T == ArraySlice) init(bytes: T) where T.Element == UInt8, T.Index == Int { self = UInt16(bytes: bytes, fromIndex: bytes.startIndex) } @_specialize(where T == ArraySlice) init(bytes: T, fromIndex index: T.Index) where T.Element == UInt8, T.Index == Int { if bytes.isEmpty { self = 0 return } let count = bytes.count let val0 = count > 0 ? UInt16(bytes[index.advanced(by: 0)]) << 8 : 0 let val1 = count > 1 ? UInt16(bytes[index.advanced(by: 1)]) : 0 self = val0 | val1 } } ================================================ FILE: Sources/CryptoSwift/UInt32+Extension.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // #if canImport(Darwin) import Darwin #elseif canImport(Android) import Android #elseif canImport(Glibc) import Glibc #elseif canImport(Musl) import Musl #elseif canImport(ucrt) import ucrt #endif protocol _UInt32Type {} extension UInt32: _UInt32Type {} /** array of bytes */ extension UInt32 { @_specialize(where T == ArraySlice) init(bytes: T) where T.Element == UInt8, T.Index == Int { self = UInt32(bytes: bytes, fromIndex: bytes.startIndex) } @_specialize(where T == ArraySlice) @inlinable init(bytes: T, fromIndex index: T.Index) where T.Element == UInt8, T.Index == Int { if bytes.isEmpty { self = 0 return } let count = bytes.count let val0 = count > 0 ? UInt32(bytes[index.advanced(by: 0)]) << 24 : 0 let val1 = count > 1 ? UInt32(bytes[index.advanced(by: 1)]) << 16 : 0 let val2 = count > 2 ? UInt32(bytes[index.advanced(by: 2)]) << 8 : 0 let val3 = count > 3 ? UInt32(bytes[index.advanced(by: 3)]) : 0 self = val0 | val1 | val2 | val3 } } ================================================ FILE: Sources/CryptoSwift/UInt64+Extension.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // /** array of bytes */ extension UInt64 { @_specialize(where T == ArraySlice) init(bytes: T) where T.Element == UInt8, T.Index == Int { self = UInt64(bytes: bytes, fromIndex: bytes.startIndex) } @_specialize(where T == ArraySlice) @inlinable init(bytes: T, fromIndex index: T.Index) where T.Element == UInt8, T.Index == Int { if bytes.isEmpty { self = 0 return } let count = bytes.count let val0 = count > 0 ? UInt64(bytes[index.advanced(by: 0)]) << 56 : 0 let val1 = count > 1 ? UInt64(bytes[index.advanced(by: 1)]) << 48 : 0 let val2 = count > 2 ? UInt64(bytes[index.advanced(by: 2)]) << 40 : 0 let val3 = count > 3 ? UInt64(bytes[index.advanced(by: 3)]) << 32 : 0 let val4 = count > 4 ? UInt64(bytes[index.advanced(by: 4)]) << 24 : 0 let val5 = count > 5 ? UInt64(bytes[index.advanced(by: 5)]) << 16 : 0 let val6 = count > 6 ? UInt64(bytes[index.advanced(by: 6)]) << 8 : 0 let val7 = count > 7 ? UInt64(bytes[index.advanced(by: 7)]) : 0 self = val0 | val1 | val2 | val3 | val4 | val5 | val6 | val7 } } ================================================ FILE: Sources/CryptoSwift/UInt8+Extension.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // #if canImport(Darwin) import Darwin #elseif canImport(Android) import Android #elseif canImport(Glibc) import Glibc #elseif canImport(Musl) import Musl #elseif canImport(ucrt) import ucrt #endif public protocol _UInt8Type {} extension UInt8: _UInt8Type {} /** casting */ extension UInt8 { /** cast because UInt8() because std initializer crash if value is > byte */ static func with(value: UInt64) -> UInt8 { let tmp = value & 0xff return UInt8(tmp) } static func with(value: UInt32) -> UInt8 { let tmp = value & 0xff return UInt8(tmp) } static func with(value: UInt16) -> UInt8 { let tmp = value & 0xff return UInt8(tmp) } } /** Bits */ extension UInt8 { /** array of bits */ public func bits() -> [Bit] { let totalBitsCount = MemoryLayout.size * 8 var bitsArray = [Bit](repeating: Bit.zero, count: totalBitsCount) for j in 0.. String { var s = String() let arr: [Bit] = self.bits() for idx in arr.indices { s += (arr[idx] == Bit.one ? "1" : "0") if idx.advanced(by: 1) % 8 == 0 { s += " " } } return s } } ================================================ FILE: Sources/CryptoSwift/Updatable.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // /// A type that supports incremental updates. For example Digest or Cipher may be updatable /// and calculate result incerementally. public protocol Updatable { /// Update given bytes in chunks. /// /// - parameter bytes: Bytes to process. /// - parameter isLast: Indicate if given chunk is the last one. No more updates after this call. /// - returns: Processed partial result data or empty array. mutating func update(withBytes bytes: ArraySlice, isLast: Bool) throws -> Array /// Update given bytes in chunks. /// /// - Parameters: /// - bytes: Bytes to process. /// - isLast: Indicate if given chunk is the last one. No more updates after this call. /// - output: Resulting bytes callback. /// - Returns: Processed partial result data or empty array. mutating func update(withBytes bytes: ArraySlice, isLast: Bool, output: (_ bytes: Array) -> Void) throws } extension Updatable { @inlinable public mutating func update(withBytes bytes: ArraySlice, isLast: Bool = false, output: (_ bytes: Array) -> Void) throws { let processed = try update(withBytes: bytes, isLast: isLast) if !processed.isEmpty { output(processed) } } @inlinable public mutating func update(withBytes bytes: ArraySlice, isLast: Bool = false) throws -> Array { try self.update(withBytes: bytes, isLast: isLast) } @inlinable public mutating func update(withBytes bytes: Array, isLast: Bool = false) throws -> Array { try self.update(withBytes: bytes.slice, isLast: isLast) } @inlinable public mutating func update(withBytes bytes: Array, isLast: Bool = false, output: (_ bytes: Array) -> Void) throws { try self.update(withBytes: bytes.slice, isLast: isLast, output: output) } /// Finish updates. This may apply padding. /// - parameter bytes: Bytes to process /// - returns: Processed data. @inlinable public mutating func finish(withBytes bytes: ArraySlice) throws -> Array { try self.update(withBytes: bytes, isLast: true) } @inlinable public mutating func finish(withBytes bytes: Array) throws -> Array { try self.finish(withBytes: bytes.slice) } /// Finish updates. May add padding. /// /// - Returns: Processed data /// - Throws: Error @inlinable public mutating func finish() throws -> Array { try self.update(withBytes: [], isLast: true) } /// Finish updates. This may apply padding. /// - parameter bytes: Bytes to process /// - parameter output: Resulting data /// - returns: Processed data. @inlinable public mutating func finish(withBytes bytes: ArraySlice, output: (_ bytes: Array) -> Void) throws { let processed = try update(withBytes: bytes, isLast: true) if !processed.isEmpty { output(processed) } } @inlinable public mutating func finish(withBytes bytes: Array, output: (_ bytes: Array) -> Void) throws { try self.finish(withBytes: bytes.slice, output: output) } /// Finish updates. May add padding. /// /// - Parameter output: Processed data /// - Throws: Error @inlinable public mutating func finish(output: (Array) -> Void) throws { try self.finish(withBytes: [], output: output) } } ================================================ FILE: Sources/CryptoSwift/Utils.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // @inlinable func rotateLeft(_ value: UInt8, by: UInt8) -> UInt8 { ((value << by) & 0xff) | (value >> (8 - by)) } @inlinable func rotateLeft(_ value: UInt16, by: UInt16) -> UInt16 { ((value << by) & 0xffff) | (value >> (16 - by)) } @inlinable func rotateLeft(_ value: UInt32, by: UInt32) -> UInt32 { ((value << by) & 0xffffffff) | (value >> (32 - by)) } @inlinable func rotateLeft(_ value: UInt64, by: UInt64) -> UInt64 { (value << by) | (value >> (64 - by)) } @inlinable func rotateRight(_ value: UInt16, by: UInt16) -> UInt16 { (value >> by) | (value << (16 - by)) } @inlinable func rotateRight(_ value: UInt32, by: UInt32) -> UInt32 { (value >> by) | (value << (32 - by)) } @inlinable func rotateRight(_ value: UInt64, by: UInt64) -> UInt64 { ((value >> by) | (value << (64 - by))) } @inlinable func reversed(_ uint8: UInt8) -> UInt8 { var v = uint8 v = (v & 0xf0) >> 4 | (v & 0x0f) << 4 v = (v & 0xcc) >> 2 | (v & 0x33) << 2 v = (v & 0xaa) >> 1 | (v & 0x55) << 1 return v } @inlinable func reversed(_ uint32: UInt32) -> UInt32 { var v = uint32 v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1) v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2) v = ((v >> 4) & 0x0f0f0f0f) | ((v & 0x0f0f0f0f) << 4) v = ((v >> 8) & 0x00ff00ff) | ((v & 0x00ff00ff) << 8) v = ((v >> 16) & 0xffff) | ((v & 0xffff) << 16) return v } @inlinable func xor(_ left: T, _ right: V) -> ArraySlice where T: RandomAccessCollection, V: RandomAccessCollection, T.Element == UInt8, T.Index == Int, V.Element == UInt8, V.Index == Int { return xor(left, right).slice } @inlinable func xor(_ left: T, _ right: V) -> Array where T: RandomAccessCollection, V: RandomAccessCollection, T.Element == UInt8, T.Index == Int, V.Element == UInt8, V.Index == Int { let length = Swift.min(left.count, right.count) let buf = UnsafeMutablePointer.allocate(capacity: length) buf.initialize(repeating: 0, count: length) defer { buf.deinitialize(count: length) buf.deallocate() } // xor for i in 0.., blockSize: Int, allowance: Int = 0) { let msgLength = data.count // Step 1. Append Padding Bits // append one bit (UInt8 with one bit) to message data.append(0x80) // Step 2. append "0" bit until message length in bits ≡ 448 (mod 512) let max = blockSize - allowance // 448, 986 if msgLength % blockSize < max { // 448 data += Array(repeating: 0, count: max - 1 - (msgLength % blockSize)) } else { data += Array(repeating: 0, count: blockSize + max - 1 - (msgLength % blockSize)) } } ================================================ FILE: Sources/CryptoSwift/XChaCha20.swift ================================================ // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // /// XChaCha20 is a Swift implementation of the XChaCha20 stream cipher, which is an extension of the ChaCha20 cipher /// that uses a 192-bit nonce instead of the original 64-bit nonce. XChaCha20 provides a higher security level by /// allowing a larger number of safe random nonces, reducing the risk of nonce reuse. /// /// For more information about the XChaCha20 algorithm, refer to the IETF draft: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha public final class XChaCha20: BlockCipher, BlockMode { public enum Error: Swift.Error { case invalidKeyOrInitializationVector case notSupported } fileprivate var chacha20: ChaCha20 // MARK: BlockCipher public static let blockSize = 64 // 512 / 8 // MARK: Cipher public let keySize: Int /// Initializes a new instance of XChaCha20 with the provided key, nonce, and optional block counter. /// - Parameters: /// - key: A 256-bit (32-byte) key for the XChaCha20 cipher. /// - nonce: A 192-bit (24-byte) nonce for the XChaCha20 cipher. /// - blockCounter: An optional initial block counter value, defaulting to 0. /// - Throws: Error.invalidKeyOrInitializationVector if the key or nonce lengths are not valid. public init(key: Array, iv nonce: Array, blockCounter: UInt32 = 0) throws { guard key.count == 32 && nonce.count == 24 else { throw Error.invalidKeyOrInitializationVector } self.keySize = key.count // From https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha#section-2.3 // XChaCha20 can be constructed from an existing ChaCha20 implementation // and HChaCha20. All one needs to do is: // // 1. Pass the key and the first 16 bytes of the 24-byte nonce to // HChaCha20 to obtain the subkey. // // 2. Use the subkey and remaining 8 byte nonce with ChaCha20 as normal // (prefixed by 4 NUL bytes, since [RFC8439] specifies a 12-byte // nonce). self.chacha20 = try .init( key: XChaCha20.hChaCha20(key: key, nonce: Array(nonce[0..<16])), iv: [0, 0, 0, 0] + Array(nonce[16..<24]), blockCounter: blockCounter ) } // MARK: BlockMode /// Options specific to the block mode. public let options: BlockModeOption = [.none] /// The custom block size for the block mode, if any. XChaCha20 does not have a custom block size. public let customBlockSize: Int? = nil public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, encryptionOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { return XChaCha20Worker( blockSize: blockSize, cipherOperation: cipherOperation, xChaCha20: self ) } /// Computes the HChaCha20 function on the provided key and nonce. /// /// See: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha#section-2.2 /// /// - Parameters: /// - key: A 256-bit (32-byte) key. /// - nonce: A 128-bit (16-byte) nonce. /// - Returns: A 256-bit (32-byte) derived key. static func hChaCha20(key: [UInt8], nonce: [UInt8]) -> [UInt8] { precondition(key.count == 32) precondition(nonce.count == 16) // HChaCha20 is initialized the same way as the ChaCha cipher, except // that HChaCha20 uses a 128-bit nonce and has no counter. Instead, the // block counter is replaced by the first 32 bits of the nonce. var state = Array(repeating: 0, count: 16) state[0] = 0x61707865 state[1] = 0x3320646e state[2] = 0x79622d32 state[3] = 0x6b206574 for i in 0..<8 { state[4 + i] = UInt32(bytes: key[i * 4..<(i + 1) * 4]).bigEndian } for i in 0..<4 { state[12 + i] = UInt32(bytes: nonce[i * 4..<(i + 1) * 4]).bigEndian } // After initialization, proceed through the ChaCha rounds as usual. for _ in 1...10 { self.innerBlock(&state) } // Once the 20 ChaCha rounds have been completed, the first 128 bits and // last 128 bits of the ChaCha state (both little-endian) are // concatenated, and this 256-bit subkey is returned. var output = Array() for i in 0..<4 { output += state[i].bigEndian.bytes() } for i in 0..<4 { output += state[12 + i].bigEndian.bytes() } return output } /// Performs the "quarter round" operation on the provided state at the specified indices. /// - Parameters: /// - state: The state on which to perform the operation. /// - a: The index of the first element in the state. /// - b: The index of the second element in the state. /// - c: The index of the third element in the state. /// - d: The index of the fourth element in the state. static func qRound(_ state: inout [UInt32], _ a: Int, _ b: Int, _ c: Int, _ d: Int) { state[a] = state[a] &+ state[b] state[d] ^= state[a] state[d] = (state[d] << 16) | (state[d] >> 16) state[c] = state[c] &+ state[d] state[b] ^= state[c] state[b] = (state[b] << 12) | (state[b] >> 20) state[a] = state[a] &+ state[b] state[d] ^= state[a] state[d] = (state[d] << 8) | (state[d] >> 24) state[c] = state[c] &+ state[d] state[b] ^= state[c] state[b] = (state[b] << 7) | (state[b] >> 25) } /// Performs the inner block operation on the provided state. /// - Parameter state: The state on which to perform the operation. static func innerBlock(_ state: inout [UInt32]) { self.qRound(&state, 0, 4, 8, 12) self.qRound(&state, 1, 5, 9, 13) self.qRound(&state, 2, 6, 10, 14) self.qRound(&state, 3, 7, 11, 15) self.qRound(&state, 0, 5, 10, 15) self.qRound(&state, 1, 6, 11, 12) self.qRound(&state, 2, 7, 8, 13) self.qRound(&state, 3, 4, 9, 14) } } // MARK: Cipher extension XChaCha20: Cipher { public func encrypt(_ bytes: ArraySlice) throws -> Array { try self.chacha20.encrypt(bytes) } public func decrypt(_ bytes: ArraySlice) throws -> Array { try self.encrypt(bytes) } } // MARK: Cryptors extension XChaCha20: Cryptors { public func makeEncryptor() throws -> Cryptor & Updatable { return try BlockEncryptor( blockSize: XChaCha20.blockSize, padding: .noPadding, self.worker( blockSize: XChaCha20.blockSize, cipherOperation: { _ in nil }, encryptionOperation: { _ in nil } ) ) } public func makeDecryptor() throws -> Cryptor & Updatable { return try BlockDecryptor( blockSize: XChaCha20.blockSize, padding: .noPadding, self.worker( blockSize: XChaCha20.blockSize, cipherOperation: { _ in nil }, encryptionOperation: { _ in nil } ) ) } } class XChaCha20Worker: CipherModeWorker { let blockSize: Int let cipherOperation: CipherOperationOnBlock let xChaCha20: XChaCha20 init(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock, xChaCha20: XChaCha20) { self.blockSize = blockSize self.cipherOperation = cipherOperation self.xChaCha20 = xChaCha20 } var additionalBufferSize: Int { return 0 } func encrypt(block plaintext: ArraySlice) -> Array { return (try? self.xChaCha20.encrypt(plaintext)) ?? .init() } func decrypt(block ciphertext: ArraySlice) -> Array { return (try? self.xChaCha20.decrypt(ciphertext)) ?? .init() } } ================================================ FILE: Sources/CryptoSwift/ZeroPadding.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // /// All the bytes that are required to be padded are padded with zero. /// Zero padding may not be reversible if the original file ends with one or more zero bytes. struct ZeroPadding: PaddingProtocol { init() { } @inlinable func add(to bytes: Array, blockSize: Int) -> Array { let paddingCount = blockSize - (bytes.count % blockSize) if paddingCount > 0 { return bytes + Array(repeating: 0, count: paddingCount) } return bytes } @inlinable func remove(from bytes: Array, blockSize _: Int?) -> Array { for (idx, value) in bytes.reversed().enumerated() { if value != 0 { return Array(bytes[0.. // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation import XCTest @testable import CryptoSwift final class AESCCMTests: XCTestCase { struct TestFixture { let tagLength: Int let key: Array let nonce: Array let aad: Array let plaintext: Array let expected: Array init(_ tagLength: Int, _ key: String, _ nonce: String, _ plaintext: String, _ expected: String, _ aad: String) { self.tagLength = tagLength self.key = Array(hex: key) self.nonce = Array(hex: nonce) self.aad = Array(hex: aad) self.plaintext = Array(hex: plaintext) self.expected = Array(hex: expected) } } func testAESCCMTestDVPT256() { let fixtures = [ //NIST Test vectors for AES-CCM with 256bit Key, from DVPT256.txt //(Integer macLength, String key, String nonce, String plain, String ciphered, String aData) { TestFixture(4, "eda32f751456e33195f1f499cf2dc7c97ea127b6d488f211ccc5126fbb24afa6", "a544218dadd3c1", "", "469c90bb", ""), TestFixture(4, "eda32f751456e33195f1f499cf2dc7c97ea127b6d488f211ccc5126fbb24afa6", "dbb3923156cfd6", "", "1302d515", ""), TestFixture(4, "eda32f751456e33195f1f499cf2dc7c97ea127b6d488f211ccc5126fbb24afa6", "a259c114eaac89", "", "4fe06e92", ""), TestFixture(4, "eda32f751456e33195f1f499cf2dc7c97ea127b6d488f211ccc5126fbb24afa6", "e1be89af98ffd7", "", "e5417f6b", ""), TestFixture(4, "eda32f751456e33195f1f499cf2dc7c97ea127b6d488f211ccc5126fbb24afa6", "1aa758eb2f9a28", "", "f8fa8e71", ""), TestFixture(16, "e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8", "a544218dadd3c1", "", "8207eb14d33855a52acceed17dbcbf6e", ""), TestFixture(16, "e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8", "dbb3923156cfd6", "", "e4dc5e03aacea691262ee69cee8ffbbe", ""), TestFixture(16, "e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8", "a259c114eaac89", "", "f79c53fd5e69835b7e70496ea999718b", ""), TestFixture(16, "e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8", "e1be89af98ffd7", "", "10d3f6fe08280d45e67e58fe41a7f036", ""), TestFixture(16, "e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8", "1aa758eb2f9a28", "", "2590df2453cb94c304ba0a2bff3f3c71", ""), TestFixture(4, "e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8", "a544218dadd3c10583db49cf39", "", "8a19a133", ""), TestFixture(4, "e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8", "79ac204a26b9fee1132370c20f", "", "154024b2", ""), TestFixture(4, "e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8", "0545fd9ecbc73ccdbbbd4244fd", "", "5c349fb2", ""), TestFixture(4, "e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8", "0a37f2e7c66490e97285f1b09e", "", "c59bf14c", ""), TestFixture(4, "e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8", "c1ad812bf2bbb2cdaee4636ee7", "", "5b96f41d", ""), TestFixture(16, "af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569", "a544218dadd3c10583db49cf39", "", "97e1a8dd4259ccd2e431e057b0397fcf", ""), TestFixture(16, "af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569", "79ac204a26b9fee1132370c20f", "", "5c8c9a5b97be8c7bc01ca8d693b809f9", ""), TestFixture(16, "af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569", "0545fd9ecbc73ccdbbbd4244fd", "", "84201662b213c7a1ff0c1b3c25e4ec45", ""), TestFixture(16, "af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569", "0a37f2e7c66490e97285f1b09e", "", "586e728193ce6db9a926b03b2d77dd6e", ""), TestFixture(16, "af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569", "c1ad812bf2bbb2cdaee4636ee7", "", "64864d21b6ee3fca13f07fc0486e232d", ""), TestFixture(4, "af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569", "a544218dadd3c1", "d3d5424e20fbec43ae495353ed830271515ab104f8860c98", "64a1341679972dc5869fcf69b19d5c5ea50aa0b5e985f5b722aa8d59", ""), TestFixture(4, "af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569", "9d773a31fe2ec7", "839d8cfa2c921c3cceb7d1f46bd2eaad706e53f64523d8c0", "5acfbe5e488976d8b9b77e69a736e8c919053f9415551209dce2d25e", ""), TestFixture(4, "af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569", "24b7a65391f88b", "3bed52236182c19418867d468dbf47c8aac46c02445f99bb", "f00628e10e8e0115b4a4532a1212a23aade4090832c1972d750125f3", ""), TestFixture(4, "af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569", "b672c91376f533", "4f7a561e61b7861719e4445057ac9b74a9be953b772b09ec", "758aa03dc72c362c43b5f85bfaa3db4a74860887a8c29e47d5642830", ""), TestFixture(4, "af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569", "a6d01fb88ca547", "a36155de477364236591e453008114075b4872120ef17264", "615cbeabbe163ba8bc9c073df9ad40833fcf3f424644ccc37aa999d7", ""), TestFixture(16, "f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453", "a544218dadd3c1", "d3d5424e20fbec43ae495353ed830271515ab104f8860c98", "bc51c3925a960e7732533e4ef3a4f69ee6826de952bcb0fd374f3bb6db8377ebfc79674858c4f305", ""), TestFixture(16, "f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453", "9d773a31fe2ec7", "839d8cfa2c921c3cceb7d1f46bd2eaad706e53f64523d8c0", "4539bb13382b034ddb16a3329148f9243a4eee998fe444aff2870ce198af11f4fb698a67af6c89ad", ""), TestFixture(16, "f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453", "24b7a65391f88b", "3bed52236182c19418867d468dbf47c8aac46c02445f99bb", "6d0f928352a17d63aca1899cbd305e1f831f1638d27c1e24432704eff9b6830476db3d30d4c103e4", ""), TestFixture(16, "f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453", "b672c91376f533", "4f7a561e61b7861719e4445057ac9b74a9be953b772b09ec", "f23ac1426cb1130c9a0913b347d8efafb6ed125913aa678a9dc42d22a5436bc12eff5505edb25e19", ""), TestFixture(16, "f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453", "a6d01fb88ca547", "a36155de477364236591e453008114075b4872120ef17264", "773b8eea2e9830297ac11d3c1f6ea4008c96040e83d76d55789d2043179fdd8fdcbd52313b7b15cb", ""), TestFixture(4, "f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453", "a544218dadd3c10583db49cf39", "3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e", "63e00d30e4b08fd2a1cc8d70fab327b2368e77a93be4f4123d14fb3f", ""), TestFixture(4, "f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453", "1501a243bf60b2cb40d5aa20ca", "f5730a05fec31a11662e2e14e362ccc75c7c30cdfccbf994", "377b2f1e7bd9e3d1077038e084f61950761361095f7eeebbf1a72afc", ""), TestFixture(4, "f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453", "d65e0e53f765f9d5e6795c0c5e", "20e394c7cc90bdfa6186fc1ba6fff158dfc690e24ba4c9fb", "6cab3060bf3b33b163b933c2ed0ba51406810b54d0edcf5c9d0ef4f7", ""), TestFixture(4, "f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453", "a6b2371acf8321864c08ddb4d8", "1a43ca628026219c5a430c54021a5a3152ae517167399635", "c5aa500d1f7c09a590e9d15d6860c4433684e04dd6bc5c8f94f223f0", ""), TestFixture(4, "f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453", "c2b60f14c894ec6178fe79919f", "3e707d98f19972a63d913e6ea7533af2f41ff98aee2b2a36", "852cca903d7fdf899807bd14642057534c8a0ccacb8c7b8fb4d35d44", ""), TestFixture(16, "1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4", "a544218dadd3c10583db49cf39", "3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e", "f0050ad16392021a3f40207bed3521fb1e9f808f49830c423a578d179902f912f9ea1afbce1120b3", ""), TestFixture(16, "1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4", "1501a243bf60b2cb40d5aa20ca", "f5730a05fec31a11662e2e14e362ccc75c7c30cdfccbf994", "254b847d4175bbb44a82b4e805514fa444c224710933f3ec8aaa3f0133234c0cd91609982adc034b", ""), TestFixture(16, "1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4", "d65e0e53f765f9d5e6795c0c5e", "20e394c7cc90bdfa6186fc1ba6fff158dfc690e24ba4c9fb", "c3618c991b15de641d291419ff6957e8b9ae5046dd8c6f08fafb76adf12f36740347e3edae62bca4", ""), TestFixture(16, "1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4", "a6b2371acf8321864c08ddb4d8", "1a43ca628026219c5a430c54021a5a3152ae517167399635", "bd37326da18e5ac79a1a9512f724bb539530868576b79c67acb5a51d10a58d6584fbe73f1063c31b", ""), TestFixture(16, "1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4", "c2b60f14c894ec6178fe79919f", "3e707d98f19972a63d913e6ea7533af2f41ff98aee2b2a36", "ecd337640022635ce1ed273756d02b7feeb2515614c1fadc95c66d3f411b478853886afd177d88c3", ""), TestFixture(4, "1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4", "a544218dadd3c1", "", "92d00fbe", "d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab"), TestFixture(4, "1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4", "3fcb328bc96404", "", "11250056", "10b2ffed4f95af0f98ed4f77c677b5786ad01b31c095bbc6e1c99cf13977abba"), TestFixture(4, "1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4", "c42ac63de6f12a", "", "4eed80fd", "7ff8d06c5abcc50d3820de34b03089e6c5b202bcbaabca892825553d4d30020a"), TestFixture(4, "1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4", "3a1701b185d33a", "", "9a5382c3", "e5d54df8ed9f89b98c5ebb1bc5d5279c2e182784ff4cd9c869ae152e29d7a2b2"), TestFixture(4, "1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4", "4f490ce07e0150", "", "e1842c46", "3e12d09632c644c540077c6f90726d4167423a679322b2000a3f19cfcea02b33"), TestFixture(16, "a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088", "a544218dadd3c1", "", "93af11a08379eb37a16aa2837f09d69d", "d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab"), TestFixture(16, "a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088", "3fcb328bc96404", "", "b3884b69d117146cfa5529901753ddc0", "10b2ffed4f95af0f98ed4f77c677b5786ad01b31c095bbc6e1c99cf13977abba"), TestFixture(16, "a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088", "c42ac63de6f12a", "", "b53d93cbfd3d5cf3720cef5080bc7224", "7ff8d06c5abcc50d3820de34b03089e6c5b202bcbaabca892825553d4d30020a"), TestFixture(16, "a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088", "3a1701b185d33a", "", "0a5d1bc02c5fe096a8b9d94d1267c49a", "e5d54df8ed9f89b98c5ebb1bc5d5279c2e182784ff4cd9c869ae152e29d7a2b2"), TestFixture(16, "a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088", "4f490ce07e0150", "", "1eda43bf07f2bf003107f3a0ba3a4c18", "3e12d09632c644c540077c6f90726d4167423a679322b2000a3f19cfcea02b33"), TestFixture(4, "a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088", "a544218dadd3c10583db49cf39", "", "866d4227", "3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907"), TestFixture(4, "a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088", "dfdcbdff329f7af70731d8e276", "", "c4ac0952", "2ae56ddde2876d70b3b34eda8c2b1d096c836d5225d53ec460b724b6e16aa5a3"), TestFixture(4, "a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088", "60f2490ba0c658848859fcbea8", "", "27c3953d", "3ad743283064929bf4fe4e0807f710f5e6a273e22614c728c3280a27b6c614a0"), TestFixture(4, "a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088", "db113f38f0504615c5c9347c3d", "", "c38fbdff", "3b71bc84e48c6dadf6ead14621d22468a3d4c9c103ac96970269730bcfce239b"), TestFixture(4, "a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088", "d35f531f714694b5e49303a980", "", "d34e90bb", "55b791ee495299916ff3c2327b4990952bebd0a2da9acfc553c6c996e354a4b5"), TestFixture(16, "8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a", "a544218dadd3c10583db49cf39", "", "867b0d87cf6e0f718200a97b4f6d5ad5", "3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907"), TestFixture(16, "8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a", "dfdcbdff329f7af70731d8e276", "", "ad879c64425e6c1ec4841bbb0f99aa8b", "2ae56ddde2876d70b3b34eda8c2b1d096c836d5225d53ec460b724b6e16aa5a3"), TestFixture(16, "8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a", "60f2490ba0c658848859fcbea8", "", "e2751f153fc76c0dec5e0cf2d30c1a28", "3ad743283064929bf4fe4e0807f710f5e6a273e22614c728c3280a27b6c614a0"), TestFixture(16, "8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a", "db113f38f0504615c5c9347c3d", "", "fc85464a81fe372c12c9e4f0f3bf9c37", "3b71bc84e48c6dadf6ead14621d22468a3d4c9c103ac96970269730bcfce239b"), TestFixture(16, "8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a", "d35f531f714694b5e49303a980", "", "b1c09b093788da19e33c5a6e82ed9627", "55b791ee495299916ff3c2327b4990952bebd0a2da9acfc553c6c996e354a4b5"), TestFixture(4, "8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a", "a544218dadd3c1", "78c46e3249ca28e1ef0531d80fd37c124d9aecb7be6668e3", "c2fe12658139f5d0dd22cadf2e901695b579302a72fc56083ebc7720", "d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab"), TestFixture(4, "8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a", "57b940550a383b", "6fb5ce32a851676753ba3523edc5ca82af1843ffc08f1ef0", "e1b4ec4279bb62902c12521e6b874171695c5da46c647cc03b91ff03", "33c2c3a57bf8393b126982c96d87daeacd5eadad1519073ad8c84cb9b760296f"), TestFixture(4, "8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a", "f32222e9eec4bd", "2c29d4e2bb9294e90cb04ec697e663a1f7385a39f90c8ccf", "224db21beb8cd0069007660e783c3f85706b014128368aab2a4e56a7", "684595e36eda1db5f586941c9f34c9f8d477970d5ccc14632d1f0cec8190ae68"), TestFixture(4, "8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a", "14c9bd561c47c1", "c22524a1ea444be3412b0d773d4ea2ff0af4c1ad2383cba8", "61b46c9024eed3989064a52df90349c18e14e4b552779d3f8f9d6814", "141ae365f8e65ab9196c4e8cd4e62189b304d67de38f2117e84ec0ec8f260ebd"), TestFixture(4, "8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a", "1ccec9923aa6e8", "518a7fb11c463bf23798982118f3cfe4d7ddde9184f37d4f", "52f8205534447d722be2b9377f7395938cc88af081a11ccb0d83fa19", "88a6d037009a1c1756f72bb4589d6d940bd514ed55386baefacc6ac3ca6f8795"), TestFixture(16, "705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe", "a544218dadd3c1", "78c46e3249ca28e1ef0531d80fd37c124d9aecb7be6668e3", "3341168eb8c48468c414347fb08f71d2086f7c2d1bd581ce1ac68bd42f5ec7fa7e068cc0ecd79c2a", "d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab"), TestFixture(16, "705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe", "57b940550a383b", "6fb5ce32a851676753ba3523edc5ca82af1843ffc08f1ef0", "fbfed2c94f50ca10466da9903ef85833ad48ca00556e66d14d8b30df941f3536ffb42083ef0e1c30", "33c2c3a57bf8393b126982c96d87daeacd5eadad1519073ad8c84cb9b760296f"), TestFixture(16, "705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe", "f32222e9eec4bd", "2c29d4e2bb9294e90cb04ec697e663a1f7385a39f90c8ccf", "dae13e6967c8b1ee0dd2d5ba1dd1de69f22c95da39528f9ef78e9e5e9faa058112af57f4ac78db2c", "684595e36eda1db5f586941c9f34c9f8d477970d5ccc14632d1f0cec8190ae68"), TestFixture(16, "705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe", "14c9bd561c47c1", "c22524a1ea444be3412b0d773d4ea2ff0af4c1ad2383cba8", "a654238fb8b05e293dba07f9d68d75a7f0fbf40fe20edaeba1586bf922412e73ce338e372615c3bc", "141ae365f8e65ab9196c4e8cd4e62189b304d67de38f2117e84ec0ec8f260ebd"), TestFixture(16, "705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe", "1ccec9923aa6e8", "518a7fb11c463bf23798982118f3cfe4d7ddde9184f37d4f", "765067ef768908d91ee4c3923943e0c7be70e2e06db99a4b3e3f51ee37fdcc5d81dd85d9e9d4f44e", "88a6d037009a1c1756f72bb4589d6d940bd514ed55386baefacc6ac3ca6f8795"), TestFixture(4, "705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe", "a544218dadd3c10583db49cf39", "e8de970f6ee8e80ede933581b5bcf4d837e2b72baa8b00c3", "c0ea400b599561e7905b99262b4565d5c3dc49fad84d7c69ef891339", "3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907"), TestFixture(4, "705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe", "0dd613c0fe28e913c0edbb8404", "9522fb1f1aa58493cba682d788186d902cfc93e80fd6b998", "fabe11c9629e598228f5209f3dbcc641fe4b1a22cadb0821d2898c3b", "2ad306575b577c2f61da7212ab63e3db3941f1f751f2356c7443531a90b9d141"), TestFixture(4, "705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe", "3e0fe3427eeda80f02dda4fed5", "38333ce78110bf53a2c2abc7db99e133ad218ca43ff7a7bc", "d88f8fcd772125212ce09c2a6e5b5693dd35073f992004f0d18fc889", "ae0d1c9c834d60ff0ecfb3c0d78c72ddb789e58adfc166c81d5fc6395b31ec33"), TestFixture(4, "705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe", "60122cbd219e5cf17415e8bc09", "794e734966e6d0001699aec3f8ab8f194de7653d3091b1b9", "76bdd9a7b34bf14ae121a87fdfa144f71b848744af6a2f0b1c0d067c", "895a45ddbe0c80793eccbf820de13a233b6aa7045cfd5313388e7184c392b216"), TestFixture(4, "705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe", "3542fbe0f59a6d5f3abf619b7d", "c5b3d71312ea14f2f8fae5bd1a453192b6604a45db75c5ed", "617d8036e2039d516709062379e0550cbd71ebb90fea967c79018ad5", "dd4531f158a2fa3bc8a339f770595048f4a42bc1b03f2e824efc6ba4985119d8"), TestFixture(16, "314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e", "a544218dadd3c10583db49cf39", "e8de970f6ee8e80ede933581b5bcf4d837e2b72baa8b00c3", "8d34cdca37ce77be68f65baf3382e31efa693e63f914a781367f30f2eaad8c063ca50795acd90203", "3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907"), TestFixture(16, "314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e", "0dd613c0fe28e913c0edbb8404", "9522fb1f1aa58493cba682d788186d902cfc93e80fd6b998", "6df09613ea986c2d91a57a45a0942cbf20e0dfca12fbda8c945ee6db24aea5f5098952f1203339ce", "2ad306575b577c2f61da7212ab63e3db3941f1f751f2356c7443531a90b9d141"), TestFixture(16, "314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e", "3e0fe3427eeda80f02dda4fed5", "38333ce78110bf53a2c2abc7db99e133ad218ca43ff7a7bc", "2bfe51f1f43b982d47f76ea8206ddbf585d6f30cec0d4ef16b1556631d3b52bf24154afec1448ef6", "ae0d1c9c834d60ff0ecfb3c0d78c72ddb789e58adfc166c81d5fc6395b31ec33"), TestFixture(16, "314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e", "60122cbd219e5cf17415e8bc09", "794e734966e6d0001699aec3f8ab8f194de7653d3091b1b9", "bf0d219bb50fcc1d51f654bb0fd8b44efa25aef39e2f11afe47d00f2eebb544e6ba7559ac2f34edb", "895a45ddbe0c80793eccbf820de13a233b6aa7045cfd5313388e7184c392b216"), TestFixture(16, "314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e", "3542fbe0f59a6d5f3abf619b7d", "c5b3d71312ea14f2f8fae5bd1a453192b6604a45db75c5ed", "39c2e8f6edfe663b90963b98eb79e2d4f7f28a5053ae8881567a6b4426f1667136bed4a5e32a2bc1", "dd4531f158a2fa3bc8a339f770595048f4a42bc1b03f2e824efc6ba4985119d8"), TestFixture(16, "c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476", "291e91b19de518cd7806de44f6", "", "ca482c674b599046cc7d7ee0d00eec1e", "b4f8326944a45d95f91887c2a6ac36b60eea5edef84c1c358146a666b6878335"), TestFixture(16, "c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476", "291e91b19de518cd7806de44f6", "", "67747defe5da5fecc00b9bf3b249f434", "36c17fd901169e5b144fdb2c4bea8cd65ad8acf7b4d3dd39acf2ad83da7b1971"), TestFixture(16, "c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476", "291e91b19de518cd7806de44f6", "", "c57ef5d0faf49149c311707493a4cfd4", "9a37c654ab8e5a0c6bdfff9793457197d206ed207d768cbc8318cfb39f077b89"), TestFixture(16, "c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476", "291e91b19de518cd7806de44f6", "", "bc2fb5571a7563bb90689a229d2f63a7", "5ab80169184541393a6975f442ee583cd432d71a6d1568fa51159df7c5b8f959"), TestFixture(16, "c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476", "291e91b19de518cd7806de44f6", "", "428888c6420c56806f465b415a66e65a", "c78a22a667aafab0c94047e03837d51b11490693d5c57ea27b901ff80b6a38f9"), TestFixture(16, "c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476", "291e91b19de518cd7806de44f6", "", "9f1b7520025e1075731adc946b80121d", "e11e30cbf63623816379f578788b0c8e6b59ee3c9c50aa6e1dcd749172d48fed"), TestFixture(16, "c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476", "291e91b19de518cd7806de44f6", "", "bd36b053b6a90f19e3b6622cba93105d", "05716168829276ff7ab23b7dd373db361e6d9e1f11d0028d374a0d3fe62be19f"), TestFixture(16, "c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476", "291e91b19de518cd7806de44f6", "", "458595a3413b965b189de46703760aa0", "3e915389639435629fcc01e1b7022d3574e2848e9151261ad801d03387425dd7"), TestFixture(16, "c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476", "291e91b19de518cd7806de44f6", "", "8b259b84a6ee5669e175affca8ba3b1a", "2f496be73a9a5d9db5927e622e166c6ec946150687b21c51c8ca7e680f9775ac"), TestFixture(16, "c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476", "291e91b19de518cd7806de44f6", "", "c5f35fdf2b63e77a18d154f0ddcfedbf", "0a8725bd8c8eab9ed52ca47835837b9f00a6c8d834ab17105b01eb4eb30402e7"), TestFixture(16, "cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14", "6df8c5c28d1728975a0b766cd7", "1a", "a5f24e87a11a95374d4c190945bf08ef2f", "080f82469505118842e5fa70df5323de175a37609904ee5e76288f94ca84b3c5"), TestFixture(16, "cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14", "6df8c5c28d1728975a0b766cd7", "40", "ffd43c5f39be92778fdce3c832d2d3a019", "f6cfb81373f1cbb0574dda514747d0099635b48cb809c6f1fa30cbb671baa505"), TestFixture(16, "cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14", "6df8c5c28d1728975a0b766cd7", "41", "fe753b7b661f1aad57c24c889b1c4fe513", "5a88b14bada16b513d4aa349b11ce4a77d4cda6f6322ff4939ad77d8ecb63748"), TestFixture(16, "cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14", "6df8c5c28d1728975a0b766cd7", "06", "b91c5ac66e89bf2769ef5f38a3f1738b24", "a92b95b997cf9efded9ff5e1bff2e49d32e65f6283552ded4b05485b011f853f"), TestFixture(16, "cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14", "6df8c5c28d1728975a0b766cd7", "c8", "773fe64379cea1a8ae3627418dd3e489a2", "a206a1eb70a9d24bb5e72f314e7d91de074f59055653bdd24aab5f2bbe112436"), TestFixture(16, "cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14", "6df8c5c28d1728975a0b766cd7", "e2", "5dabc529442ff93005551b7689bcb748f7", "d3029f384fd7859c287e38c61a9475d5ddbfd64af93746b1dc86b8842a8c194c"), TestFixture(16, "cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14", "6df8c5c28d1728975a0b766cd7", "1a", "a5ee68e416617ac974b3d1af7320cd51f6", "51ca3d3b70b5e354451a5177d7acfd8e7b44eae55e29d88b5e8eb8fc1e5c62fc"), TestFixture(16, "cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14", "6df8c5c28d1728975a0b766cd7", "dd", "6243883d93d7066991e0fac453400b4fbf", "8c6c6791f1ac957b18bf008e260a0af4a5b7bfdb1e0008d6eaaa227f45cf4f62"), TestFixture(16, "cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14", "6df8c5c28d1728975a0b766cd7", "4c", "f3b940d416f3435812f9d1b18f441b7721", "b0a1af969a95025385b251afd1e89f353426ed6e5d71019cd73366aa31d5b464"), TestFixture(16, "cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14", "6df8c5c28d1728975a0b766cd7", "88", "371d27e9a32feea28a6a7e7da2d27e1cc4", "7e72b2ca698a18cb0bf625f5daddb0d40643009db938340a9e4fe164a052fee1"), TestFixture(16, "36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510", "021bd8b551947be4c18cf1a455", "be80", "ecacc3152e43d9efea26e16c1d1793e2a8c4", "b5c6e8313b9c68e6bb84bffd65fa4108d243f580eab99bb80563ed1050c8266b"), TestFixture(16, "36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510", "021bd8b551947be4c18cf1a455", "82c9", "d0e5d06bf4b50ccce0b2acfd16ce90a8854d", "38e5032c5949c2668191ef1af5bb17eddc28abdb4e5bb41eaffec2523b2525d6"), TestFixture(16, "36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510", "021bd8b551947be4c18cf1a455", "8239", "d0158d784f486c1dc4a2bafd5b02ca1e1c05", "0b50f5173249fb7118f80d25874d6745d88e4ce265fa0dd141ad67ae26c31122"), TestFixture(16, "36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510", "021bd8b551947be4c18cf1a455", "16c1", "44eda3377002a48f9fe306d157358e6df37d", "0296743a3125b103a2b2a78a109e825ea10834bd684215ab2e85cc4172e37348"), TestFixture(16, "36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510", "021bd8b551947be4c18cf1a455", "2801", "7a2df6c09bf1dcb1c82bd98c6e2c13a8d7a5", "a94e64becb803e211785ba51db7f3db042fbf44a7a821509156a6828b0f207e9"), TestFixture(16, "36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510", "021bd8b551947be4c18cf1a455", "65e7", "37cb2ea363c0d8864363056467570959ba03", "105358cc17b12107e023a23d57b44c66a2c58d8db05100311575e1ea152fc350"), TestFixture(16, "36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510", "021bd8b551947be4c18cf1a455", "819d", "d3b16519377e6d0252b5f80cdf3d0253eccf", "669f9a63cf638a202dca1965c4116273249813ce0b39703887d89bdf5b3b12d6"), TestFixture(16, "36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510", "021bd8b551947be4c18cf1a455", "761e", "24329a4dee6ca2cde473f08f76f779856c3c", "e288590a3eba28ac6847a50b0294ab6bd0a548716ff5102c44a5b656b2d9ddd6"), TestFixture(16, "36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510", "021bd8b551947be4c18cf1a455", "56de", "04f29e65c0f01e644e74092253b470cd5511", "5b222aae3c7786c3b9021ba672f9136190ec931cf055f84c85706127f74c6d5b"), TestFixture(16, "36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510", "021bd8b551947be4c18cf1a455", "b275", "e059809fa107f379957b52ac29fe0bc8a1e2", "2082f96c7e36b204ad076d8b2f796cccf5cbc80b8384b53a504e07706b07f596"), TestFixture(16, "ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944", "0bddf342121b82f906368b0d7b", "db457c", "54473c3f65d6be431e79700378049ac06f2599", "887486fff7922768186363ef17eb78e5cf2fab8f47a4eb327de8b16d63b02acb"), TestFixture(16, "ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944", "0bddf342121b82f906368b0d7b", "62a6c5", "eda4853b186edc15c22ba24e470eb5a072da9f", "0683c20e82d3c66787cb047f0b1eb1c58cdde9fb99ee4e4494bbf27eb62777d1"), TestFixture(16, "ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944", "0bddf342121b82f906368b0d7b", "cc67bc", "4365fc52a1fb5a58bd51931230c1a7dfb1a8c1", "413074619b598f8bed34cab51ddf59941861ba0169ebe7570a5ed01d790c08e5"), TestFixture(16, "ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944", "0bddf342121b82f906368b0d7b", "33800b", "bc824b7d3810f59176cb108c7e969da51d4d79", "2d65a5175c29a095dc082dab9cfcf4b895efbfa715c57614589d4db159543ce9"), TestFixture(16, "ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944", "0bddf342121b82f906368b0d7b", "b2c826", "3dca6646ffea832595c9c86e6517215541ddbd", "6a831b6059456be98e6fce608d8c71cb8efb04a96b45c2dfbdaeabf5420a1482"), TestFixture(16, "ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944", "0bddf342121b82f906368b0d7b", "d7e620", "58e460e89a6725f0fc35622d89d2f3e34be90a", "3a04a01160402bf36f33337c340883597207972728c5014213980cd7744e9e41"), TestFixture(16, "ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944", "0bddf342121b82f906368b0d7b", "795af4", "f658b4b1bd7ad5d81686aeb44caa6025d488bd", "64d8bd3c646f76dc6ce89defd40777fe17316729e22ba90f6a2443ee03f6390b"), TestFixture(16, "ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944", "0bddf342121b82f906368b0d7b", "66efcd", "e9ed8d0553c801f37c2b6f82861a3cd68a75e3", "7bef8d35616108922aab78936967204980b8a4945b31602f5ef2feec9b144841"), TestFixture(16, "ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944", "0bddf342121b82f906368b0d7b", "78b00d", "f7b24de3eeb8ea6c08b466baf246b3667feb3f", "92f7dc22dcbbe6420aca303bd586e5a24f4c3ed923a6ebe01ec1b66eee216341"), TestFixture(16, "ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944", "0bddf342121b82f906368b0d7b", "9dd5e1", "12d7a11db811640c533794bfec6eeb977233ec", "71bf573cf63b0022d8143780fc2d9c7dbd0505ac31e9dce0ad68c2428b0878a0"), TestFixture(16, "62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0", "5bc2896d8b81999546f88232ab", "87294078", "2bc22735ab21dfdcfe95bd83592fb6b4168d9a23", "fffb40b0d18cb23018aac109bf62d849adca42629d8a9ad1299b83fe274f9a63"), TestFixture(16, "62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0", "5bc2896d8b81999546f88232ab", "0f28ee1c", "a3c38951b5de3331078aa13bd3742b59df4f661a", "75c3b3059e59032067e9cd94d872e66f168e503bcf46bc78d82a4d4a15a29f6e"), TestFixture(16, "62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0", "5bc2896d8b81999546f88232ab", "d41c9c87", "78f7fbcae52afe7326a12a9aaf22255a38d4bd0d", "8fb9569f18a256aff71601d8412d22863e5a6e6f639214d180b095fa3b18d60e"), TestFixture(16, "62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0", "5bc2896d8b81999546f88232ab", "046bc0d8", "a880a7957543692a72f0d599de48b5e5f5a9413f", "8b62d9adf6819c46c870df8a1486f0a329672f7d137bb7d8659f419c361a466c"), TestFixture(16, "62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0", "5bc2896d8b81999546f88232ab", "39bd4db8", "95562af530fc357f5482b9004d466bf858586acb", "fd98f8f39dfa46ea5926e0ffacbabbe8c34205aade08aa0df82e1d4eaaf95515"), TestFixture(16, "62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0", "5bc2896d8b81999546f88232ab", "b43cdd3a", "18d7ba77a9e8db046fdd548b52d40375c1e9a448", "09bf4f77a9883733590a3cc7ee97f3c9b70f4db255620e88cd5080badc73684c"), TestFixture(16, "62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0", "5bc2896d8b81999546f88232ab", "e0052e9b", "4cee49d64efbdd4ad8d3e863172d9372fca07c20", "40326d765e0f6cf4b4deccb128bebf65a7b3c3e5bcf1d58f6158e1e9153b7e85"), TestFixture(16, "62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0", "5bc2896d8b81999546f88232ab", "696825f6", "c58342bb95bd661b32bc18025808f8b4035acad6", "aa5ae6dcdc21b5446489bdabf5c6747bdf3bbfdb3de2c03170efefe5ccb06d69"), TestFixture(16, "62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0", "5bc2896d8b81999546f88232ab", "7eb07739", "d25b1074ac05b072264e31a4b2801a6d790512d7", "d3d34f140a856e55b29471fde4c0e5f7306b76d03faab26db79c10f95ffb3122"), TestFixture(16, "62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0", "5bc2896d8b81999546f88232ab", "9cad70b1", "304617fcc00514d260e1d211de361c254369e93a", "648a84813ca97aef4ab7e143ee29acb946388660f18eb671194646e0b0136432"), TestFixture(16, "bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576", "4f18bcc8ee0bbb80de30a9e086", "3e8c6d1b12", "45f3795fcf9c66e1a43103d9a18f5fba5fab83f994", "574931ae4b24bdf7e9217eca6ce2a07287999e529f6e106e3721c42dacf00f5d"), TestFixture(16, "bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576", "4f18bcc8ee0bbb80de30a9e086", "76fc98ec66", "0d838ca8bb6f3cd579294f706213ed0f0bf32f00c5", "99cd9d15630a55e166114f04093bd1bb6dbb94ecaad126fe5c408dee5f012d9f"), TestFixture(16, "bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576", "4f18bcc8ee0bbb80de30a9e086", "6564c247cc", "1e1bd603117d38e026f706c9273dbcb6dc982751d0", "1516fdf7a7a99f3c9acc7fff686203dec794c3e52272985449ddf5a268a47bc3"), TestFixture(16, "bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576", "4f18bcc8ee0bbb80de30a9e086", "c11b9c9d76", "ba6488d9abc3e46166767c6ad2aeffb347168b1b55", "0c9c35be98591bf6737fc8d5624dcdba1a3523c6029013363b9153f0de77725b"), TestFixture(16, "bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576", "4f18bcc8ee0bbb80de30a9e086", "45a4e0d7dd", "3edbf4930033a7dca78bcbf4d75d651ee5fadff31b", "e74afe3ba960e6409dba78ecb9457e2a4ce2e09792b1d2e3858f4c79f7ddba62"), TestFixture(16, "bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576", "4f18bcc8ee0bbb80de30a9e086", "e5861b2327", "9ef90f67fa11585167c83105ee16828a574c84ac86", "96cbe9cd193513599c81f5a520fabaff51ee8cbdb81063c8311b1a57a0b8c8fd"), TestFixture(16, "bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576", "4f18bcc8ee0bbb80de30a9e086", "f5b5bcc38e", "8ecaa88753ffaba456f78e431f4baa5665f14e1845", "2e7ea84da4bc4d7cfb463e3f2c8647057afff3fbececa1d20024dac29e41e2cf"), TestFixture(16, "bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576", "4f18bcc8ee0bbb80de30a9e086", "b6cc89c75d", "cdb39d838034714731f9503993df357954ecb19cd3", "be125386f5be9532e36786d2e4011f1149abd227b9841150d1c00f7d0efbca4a"), TestFixture(16, "bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576", "4f18bcc8ee0bbb80de30a9e086", "3802f2aa9e", "437de6ee436c1b008b7572752f04362b2bfdc296bb", "3fa8628594b2645bc35530203dca640838037daeaf9cf8acaa0fb76abf27a733"), TestFixture(16, "bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576", "4f18bcc8ee0bbb80de30a9e086", "e082b8741c", "9bfdac30c1a3f7c3c29dc312c1f51a675400500e32", "642ae3466661ce1f51783deece86c38e986b8c0adea9e410e976f8a2fe0fe10f"), TestFixture(16, "5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c", "7a76eac44486afdb112fc4aab9", "1b62ad19dcac", "4ad1fcf57c12b14e0e659a6305b4aeffae82f8a66c94", "a66c980f6621e03ff93b55d5a148615c4ad36d6cbdd0b22b173b4b1479fb8ff7"), TestFixture(16, "5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c", "7a76eac44486afdb112fc4aab9", "3ef0faaa9b79", "6f43ab463bc779fa7932d365e2da9b05c00a7318384a", "c13f65bd491cb172a0f7bbc4a056c579484b62695e90383358d605307d5be0a5"), TestFixture(16, "5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c", "7a76eac44486afdb112fc4aab9", "1a98ddbf35f1", "4b2b8c53954f813229912137b7a4945dc07cea24a974", "59dcca8fc50740831f8f259eb55d4db11f763a83187d93758d78d166f4d73cd5"), TestFixture(16, "5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c", "7a76eac44486afdb112fc4aab9", "f46a7b1c28ea", "a5d92af088546e045f19f737a24c8addf832ed3f7a42", "578509ca4f57aadb78056794bf18b0714090970db786e2e838105e672165761c"), TestFixture(16, "5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c", "7a76eac44486afdb112fc4aab9", "e98f5e5a20d0", "b83c0fb6806edaae8a7dcd3b0fbb59438f88743ec6e8", "696c0c6427273cf06be79f2206c43af9cbda0b884efaf04deba0c4bf0a25cb26"), TestFixture(16, "5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c", "7a76eac44486afdb112fc4aab9", "06319c0480e2", "5782cde8205cd9cb636ca6543c4e35964f47341f2814", "95a66b60249ed086eecaeb9bc449afcee9de212619e87516ca947351b25120df"), TestFixture(16, "5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c", "7a76eac44486afdb112fc4aab9", "f4c723433b7c", "a57472af9bc2ec82eadf4eb1f055da1a92a82052ab8b", "2b411bea57b51d10a4d2fb17ef0f204aa53cf112e1130c21d411cdf16a84176d"), TestFixture(16, "5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c", "7a76eac44486afdb112fc4aab9", "02f809b01ce3", "534b585cbc5d01b10a7ae24a4ca2bfb07ea2a3b31a97", "ff3bff3a26fc5a91252d795f7e1b06f352314eb676bff50dc9fbe881c446941e"), TestFixture(16, "5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c", "7a76eac44486afdb112fc4aab9", "2b6004823a29", "7ad3556e9a97231323a4b88af5d7d0b07c0e73ddce1d", "f6be4aad63d33a96c0b5e9c4be62323c9e2308b29961fff980ba0dbda0549274"), TestFixture(16, "5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c", "7a76eac44486afdb112fc4aab9", "236c60cba4fa", "72df31270444db30eb33d2ede33abbe22f37704fe68b", "c3706a28d7420b41e072dcecc06b6b13116cca110bde8faea8e51f5107352d71"), TestFixture(16, "f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2", "d0d6871b9adc8623ac63faf00f", "d48daa2919348d", "eb32ab153a8e092fa325bafc176a07c31e6cc0a852d288", "e97175c23c5b47da8ce67811c6d60a7499b3b7e1347ad860519285b67201fe38"), TestFixture(16, "f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2", "d0d6871b9adc8623ac63faf00f", "f95b716bfe3475", "c6e47057dd8ef1a24840f4f40a7963becde3a85968b29c", "ba45e1859efae362a44a0116a14e488ba369da6c76c3913b6df8e69e5e1111fa"), TestFixture(16, "f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2", "d0d6871b9adc8623ac63faf00f", "4862e3677083f0", "77dde25b5339748f2a4a5c276727e0a210fc2efb5aeabe", "efcaa6f6cda3036b0b52ff9f36bc38ca74049c32c6b7cdfb8a46ca4144bacd64"), TestFixture(16, "f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2", "d0d6871b9adc8623ac63faf00f", "7f1ca0728f6d65", "40a3a14eacd7e1051734fc31232ab2ab63474020ab4dc9", "360bcb407603fe92f856bf677625b9882521e6dae8f35fdfc3dc737f9398f609"), TestFixture(16, "f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2", "d0d6871b9adc8623ac63faf00f", "67478ef73290fa", "58f88fcb112a7ec715244f307609ffa253e4e3659b0ece", "f12ee9d37946cfd88516cbe4a046f08c9bbba76a3973ff1e2cb14493405bd384"), TestFixture(16, "f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2", "d0d6871b9adc8623ac63faf00f", "36bb9e511276c5", "09049f6d31cc41f11047da612d2987fa2e50ada5ae7f9d", "5833dde0c577b2be4eb4b3d01d7b0042fa8441ad7043ea462bbbbd56a59790ea"), TestFixture(16, "f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2", "d0d6871b9adc8623ac63faf00f", "d68d6556c5a5b1", "e932646ae61f35382f7648718127ebae7eb7443ebd2c2c", "1e103c63d8ead36b985f921044cd32b8f9f04a2ba9fa154a09e676ffaa093970"), TestFixture(16, "f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2", "d0d6871b9adc8623ac63faf00f", "0568cca4ff79dc", "3ad7cd98dcc358cc40a5e7fffb1fb9a5dd9d6ba91bede1", "a1cfb61d45a140bdea6329ba0fe80429ff9aa4624a1d31bc752f7c97f1d390a0"), TestFixture(16, "f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2", "d0d6871b9adc8623ac63faf00f", "bd93d08eea4263", "822cd1b2c9f8e7468d2b70c311732f11ed72b57d83e500", "116b5b015e44ceef0061b2d2e73fa0b386d5c1e187782beebdfc6efb5a1c6935"), TestFixture(16, "f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2", "d0d6871b9adc8623ac63faf00f", "4fb62753024e92", "7009266f21f416b41a70f548e359add30c0e5746fbeb2b", "3d55882e6f3f89309b6940a3b408e573458eedd10fc3d0e1f3170eb313367475"), TestFixture(16, "493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b", "fe2d8ae8da94a6df563f89ce00", "e5653e512d8b0b70", "75d31f8d47bee5c4e2ba537355ae8ab25cc9ed3511ff5053", "579a637e37a0974cd2fc3b735d9ed088e8e488ffe210f043e0f9d2079a015ad6"), TestFixture(16, "493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b", "fe2d8ae8da94a6df563f89ce00", "2c4ba9ce52e01645", "bcfd881238d5f8f1781a9e359804831f31a1efb1ae1cb71d", "1583138aa307401dddc40804ac0f414d338fc3ffb2946f09aaaa7079426fc1ee"), TestFixture(16, "493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b", "fe2d8ae8da94a6df563f89ce00", "5eb2d054a0e58c62", "ce04f188cad062d62dcc77c4e1fe2bafd477598977835f0c", "78d3dda40e433bba7a330ca3e5bd5170f0895f2e3e438402344ced79fcb0c719"), TestFixture(16, "493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b", "fe2d8ae8da94a6df563f89ce00", "bbbf7830d04ab907", "2b0959ecba7f57b308946723baf0dbf613359b6e040f9bd5", "dfc762466fa84c27326e0ee4320aa71103d1e9c8a5cf7d9fab5f27d79df94bd6"), TestFixture(16, "493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b", "fe2d8ae8da94a6df563f89ce00", "10c654c78a9e3c06", "8070751be0abd2b2003bd62ca51f74088bbbd33e54ac9dd4", "7e8ea82d1137c1e233522da12626e90a5f66a988e70664cb014c12790d2ab520"), TestFixture(16, "493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b", "fe2d8ae8da94a6df563f89ce00", "668d32e322e1da3e", "f63b133f48d4348a67e65e7f2cdedf6ef8cc0ee7a6dcfb02", "873da112557935b3929f713d80744ed08b4b276b86331dbc386fba361726d565"), TestFixture(16, "493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b", "fe2d8ae8da94a6df563f89ce00", "e39f6225e8eab6cc", "732943f982df58780532f8c6639e5d6c7b755fcf516724e3", "cfba97919f703d864efc11eac5f260a5d920d780c52899e5d76f8fe66936ff82"), TestFixture(16, "493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b", "fe2d8ae8da94a6df563f89ce00", "6021a00f6d0610a4", "f09781d30733fe107fd7a33828413ebc252dd9d015773524", "01abcfee196f9d74fcaa7b69ae24a275485c25af93cc2306d56e41e1eb7f5702"), TestFixture(16, "493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b", "fe2d8ae8da94a6df563f89ce00", "bbaf0ac4e77ee78d", "2b192b188d4b0939d3d51368799325ad1c8233fa071bade0", "ce1c31e7121c071d89afab5a9676c9e96cac3d89dcae83136bbb6f5ca8f81e5d"), TestFixture(16, "493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b", "fe2d8ae8da94a6df563f89ce00", "98a2336549a23a76", "081412b92397d4c25d1ea568637f773174a7f920a51b1fe1", "bb210ca5bc07e3c5b06f1d0084a5a72125f177d3e56c151221115ae020177739"), TestFixture(16, "b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a", "274846196d78f0af2df5860231", "615d724ae94a5daf8d", "f019ae51063239287d896e7127f17d13f98013b420219eb877", "69adcae8a1e9a3f2fe9e62591f7b4c5b19d3b50e769521f67e7ea8d7b58d9fc8"), TestFixture(16, "b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a", "274846196d78f0af2df5860231", "0d9168eeab3b27ba69", "9cd5b4f54443433d997cc2cd61da9358b4045fef32f8192cbf", "162d0033c9ea8d8334d485b29eef727302135a07a934eea5fee6041e9f1f47c1"), TestFixture(16, "b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a", "274846196d78f0af2df5860231", "6287dcffdd5fb97885", "f3c300e43227ddff75d280f0ffdd560fb8915978e3bd6205bb", "3f4ab57efa32f51a4c00790280e77c0e55b85bbda4f854e242368e9a289b5a81"), TestFixture(16, "b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a", "274846196d78f0af2df5860231", "6e5e01b3fd71d16b9c", "ff1adda81209b5ec6c7dbf90420a1ff2e24bd6303b80cfc199", "945d18134c148f164b39fd7c4aef0335045553f6ea690a3b1726418d86f0de00"), TestFixture(16, "b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a", "274846196d78f0af2df5860231", "b51521e689b5247362", "2451fdfd66cd40f492d741f4329ae7cc77d42bf7e5f2ec5ab6", "23af12893431b07c2922ab623aed901c0eaaeb9a24efc55273e96aea4dab7038"), TestFixture(16, "b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a", "274846196d78f0af2df5860231", "7f973617e710fb76fe", "eed3ea0c08689ff10ec9ffdcc2f36edac14613b1d85baf25a9", "b15a118b3132c20c31e6c9d09acdee0e15fcc59d6f18306442682512d22eb10f"), TestFixture(16, "b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a", "274846196d78f0af2df5860231", "7e909b6727ac3fd02f", "efd4477cc8d45b57df5a61a28bb10265b26043d7a8dd357713", "dcfbeb6490f5fa7eaf917462473a6cec98bebf8f17493fe9b994119a6d5a5457"), TestFixture(16, "b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a", "274846196d78f0af2df5860231", "a5075638932b5632f8", "34438a237c5332b508d321c371ae1fd01bdf3b6c75a597da6e", "77e9317294f046f315a0d79e3423f29f7d9ebcd36d6eaa2a3fb2f4500309478c"), TestFixture(16, "b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a", "274846196d78f0af2df5860231", "c10f15a0de78db8aa3", "504bc9bb3100bf0d539393d1635bc40ac62405a39155406c47", "3aa8f204eb127b547e13873ed0238018394e13686c8734e49e3e629deb352c77"), TestFixture(16, "b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a", "274846196d78f0af2df5860231", "8294f830cfca42cfbe", "13d0242b20b226484eff89641e1bd5ad6cc827441b17c45ecf", "7f67e6f97c6c258f014d721a4edaaa0ddb3f9f09993276ab7b714ea9356c231d"), TestFixture(16, "dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9", "b3503ed4e277ed9769b20c10c0", "2e3cf0af8c96c7b22719", "e317df43ab46eb31be7e76f2730d771d56099a0c8d2703d7a24e", "9ae5a04baa9d02c8854e609899c6240851cbc83f81f752bc04c71affa4eed385"), TestFixture(16, "dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9", "b3503ed4e277ed9769b20c10c0", "e081c43a07450ce0dfa2", "2daaebd62095206346c5bcc7a8260ef361dc39fdb776d041f0d4", "da77c6d5627a2aa34911bd1f7cc5f8aa68a2c6546adc96a186b9af8e5baac4cf"), TestFixture(16, "dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9", "b3503ed4e277ed9769b20c10c0", "c381d2ae5e72fc82324a", "0eaafd4279a2d001ab2d19f0cbb0899f221aac9762f2650f8058", "134d2d9726400d09dd3521326f96fbef993ddc0c4088770057b0f8d70356456f"), TestFixture(16, "dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9", "b3503ed4e277ed9769b20c10c0", "737f4d00c54ddca80eec", "be5462ece29df02b978b3dc92a9bd26b9653e5917359c331fcff", "0d065dfde1de1f21784c7869eb566c977f807cfbd53578f4616995b51d7dc045"), TestFixture(16, "dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9", "b3503ed4e277ed9769b20c10c0", "4e9e251ebbbbe5dbc8ff", "83b50af29c6bc958519891dda72c27d272561e00f7041845d998", "95c54d187f2415535451cbb9cb35869749b171f7043216ce6886dd77baeecf60"), TestFixture(16, "dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9", "b3503ed4e277ed9769b20c10c0", "0db72b281ab4046d15a6", "c09c04c43d6428ee8cc1928ac628758ad58fc1b5a768d4722848", "0f98039e6a9fe360373b48c7850ce113a0ff7b2ae5ce773dd4c67ca967cd691b"), TestFixture(16, "dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9", "b3503ed4e277ed9769b20c10c0", "4f7b4f38ff1ba4df5a59", "825060d4d8cb885cc33ed11dad4dc8b265a53cf0bdd85c5f15f4", "ad840bc55654762e5eba0e4a9e7998992d990a06d70da1b1ca922ef193dab19a"), TestFixture(16, "dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9", "b3503ed4e277ed9769b20c10c0", "58ce55379ef24b72d6d6", "95e57adbb92267f14fb18eb659a5a7084be48d099467da4395df", "911e9876ea98e1bcf710d8fd05b5bf000ea317d926b41b6015998ee1462ab615"), TestFixture(16, "dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9", "b3503ed4e277ed9769b20c10c0", "a219028a953ce1544835", "6f322d66b2eccdd7d1523b2b2583fd117cec47b1c84d3863159e", "3f68a4fb4043bcf9b6d277c97e11365d949c705bd6679c6f0aaf52e62330ad79"), TestFixture(16, "dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9", "b3503ed4e277ed9769b20c10c0", "83b0ee9a52252c456105", "4e9bc17675f500c6f8625456eb2b6a2d35c649a84051f843153c", "02f32242cba6204319075ea8ce806a57845355ae73e6b875955df510096ebff9"), TestFixture(16, "4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207", "bdb1b82ba864893c2ee8f7426c", "8015c0f07a7acd4b1cbdd2", "8e9f80c726980b3d42e43a6512a0481255b729a10f9edb5f07c60c", "9bcc5848e928ba0068f7a867e79e83a6f93593354a8bfcfc306aeeb9821c1da1"), TestFixture(16, "4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207", "bdb1b82ba864893c2ee8f7426c", "c97b62a719720b44b7779c", "c7f122904590cd32e92e748c514444f00ffdb80a4bb7e9eb651946", "c2e75952ab49216f305e3776865791ce877cef8c0229ca97561787093fddf1d8"), TestFixture(16, "4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207", "bdb1b82ba864893c2ee8f7426c", "cb7c17ef62464ecc8008f6", "c5f657d83ea488bade511edb609dfc1929ac1ba5753fc83bf945b7", "c76a3ff4e6d1f742dd845be2d74c1a9b08e418909b15077deb20373ef55caf91"), TestFixture(16, "4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207", "bdb1b82ba864893c2ee8f7426c", "893a690cc5221de597d0e8", "87b0293b99c0db93c9890053b74283296d0fca83b262915289163c", "bdb69f99f9a144b9ad88c6cfd8ffb8304c201de9b2818552ce6379e6042c1951"), TestFixture(16, "4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207", "bdb1b82ba864893c2ee8f7426c", "80f3e4245c3eab16ef8bf0", "8e79a41300dc6d60b1d21888a34955893059d66549795b3ac2105c", "01815f599d6ba0d1c09f6f673bb6cca4c2a7a74f4e985be4c0f37842c7bbc5a4"), TestFixture(16, "4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207", "bdb1b82ba864893c2ee8f7426c", "641c6914920a79943dca39", "6a962923cee8bfe26393d1377c4e2f20aaa872a9a0b1d1d7f56df0", "a9db62e9ab53c4a805c43838ce36b587d29b75b43fb34c17a22d3981120f3bc5"), TestFixture(16, "4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207", "bdb1b82ba864893c2ee8f7426c", "2286a1eddd80737a724ca9", "2c0ce1da8162b50c2c15415545aa0c1dd11551891ae553d3a91908", "f0c2cc5a1b4c4cbe839338fa0d7a343514801302aef2403530605cf4f44d2811"), TestFixture(16, "4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207", "bdb1b82ba864893c2ee8f7426c", "d8c63e7d7d332198249c0c", "d64c7e4a21d1e7ee7ac5e4d9e07ec5806360843676ef27d811b246", "9842922499ad4d487488b3731f48765efe0b4eb59e7b491ba5f6636f09ed564d"), TestFixture(16, "4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207", "bdb1b82ba864893c2ee8f7426c", "4b81804d777a59b6a107cf", "450bc07a2b989fc0ff5e27483b8727c5753ede25e1fab0d86963be", "399b71ecb41f4590abda79045cdf6495f27daaa559c1b34f513b5c4ac105ec10"), TestFixture(16, "4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207", "bdb1b82ba864893c2ee8f7426c", "dfc762466fa84c27326e0e", "d14d2271334a8a516c37e64b5c3c1dc577ee8fcf6ef3ebc0783430", "2c186c5c3463a4a8bad771feb71e2973c4f6dede2529827707bf4fa40672660f"), TestFixture(16, "d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906", "0b5f69697eb1af24e8e6fcb605", "a203aeb635e195bc33fd42fa", "62666297a809c982b50722bd56bc555899345e0404b2938edf33168e", "ea26ea68facdac3c75ba0cdf7b1ad703c9474af83b3fbfc58e548d776b2529b9"), TestFixture(16, "d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906", "0b5f69697eb1af24e8e6fcb605", "aac414fbad945a49ae178103", "6aa1d8da307c067728ede1449b15447c904b671824c2ca24c4fc7ad4", "0b32069fc7e676f229f1037d3026c93eef199913e426efd786b524ce1dbde543"), TestFixture(16, "d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906", "0b5f69697eb1af24e8e6fcb605", "7ee0ce371329192618e3cda0", "be8502168ec145189e19ade7ea13850e99ef9300c65f5abc9419d13a", "7a8658302e5181552292aa56e8209de63b5d86934167549b0d936202681757e1"), TestFixture(16, "d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906", "0b5f69697eb1af24e8e6fcb605", "b0a1af969a95025385b251af", "70c463b7077d5e6d034831e8486c93c31bbedc9e5ffa2f4154bceea9", "4f05600950664d5190a2ebc29c9edb89c20079a4d3e6bc3b27d75e34e2fa3d02"), TestFixture(16, "d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906", "0b5f69697eb1af24e8e6fcb605", "9f6c6d60110fd3782bdf49b0", "5f09a1418ce78f46ad2529f7f18b556e7da59fd2549dc57a17bf64f8", "4530e4dc6a4c3733b8ab7e77e384223cc1a8c179fb66818c08aca47e5c705d89"), TestFixture(16, "d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906", "0b5f69697eb1af24e8e6fcb605", "90958d7f458d98c48cbb464c", "50f0415ed865c4fa0a41260b30aad3a838680cbd313004685a5510c5", "f179353aef342f0f691caf1fcb811e3f6504e14d6d9381c5439b098ff978b01b"), TestFixture(16, "d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906", "0b5f69697eb1af24e8e6fcb605", "9f7ae892e5662803408d4d06", "5f1f24b3788e743dc6772d411d57b89ed0c91251aed37a6ca68a50c7", "f6df267e5cbc9d2a67b1c0fd762f891ee3b7c435884cb87d8228091b34aeddae"), TestFixture(16, "d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906", "0b5f69697eb1af24e8e6fcb605", "817074e351455f23cb67883d", "4115b8c2ccad031d4d9de87ad79a3b0feea16ff5fbca16211ea6fdd9", "4372e152b1afd99c7f87c8a51dbc3a5c14c49d04ea1c482a45dfbcda54972912"), TestFixture(16, "d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906", "0b5f69697eb1af24e8e6fcb605", "1b7da3835e074fdf62f1eb3c", "db186fa2c3ef13e1e40b8b7b49f22737c4b2f9fa0a7e3dd4b067fbaa", "82b6cd1c6618c42ba74e746075dc28700333578131ca6fde6971d2f0c6e31e6a"), TestFixture(16, "d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906", "0b5f69697eb1af24e8e6fcb605", "57473e7a105c806867379194", "9722f25b8db4dc56e1cdf1d3ef43a48dbea8c1547455ad0197af88a2", "a5422e53975e43168726677930f6d3e13281bdbd13c67c168340ed67e45d15b0"), TestFixture(16, "e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df", "55b59eb434dd1ba3723ee0dc72", "8714eb9ecf8bdb13e919de40f9", "ba6063824d314aa3cbab14b8c54c6520dac0f073856d9b9010b7857736", "9b1d85384cb6f47c0b13514a303d4e1d95af4c6442691f314a401135f07829ec"), TestFixture(16, "e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df", "55b59eb434dd1ba3723ee0dc72", "a0837676e091213890dc6e0a34", "9df7fe6a622bb088b26ea4f20820a423dd30796b6016baff106aaef206", "fa17c693d0997140fbc521d39e042d8e08388106874207ca81c85f45c035d6e6"), TestFixture(16, "e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df", "55b59eb434dd1ba3723ee0dc72", "b8a2ce7e051b8d094ec43f2a7f", "85d6466287a11cb96c76f5d2436032bc79c4aef1f74da25e92b0aa7f8a", "27663597b389b78e96c785ca2f5510c8963a5561d2b0b24c4dcdf8e58562c12c"), TestFixture(16, "e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df", "55b59eb434dd1ba3723ee0dc72", "9e4103ab1dfb77ae3494507332", "a3358bb79f41e61e16269a8b0e658123d2e5bb324c7ead8897f8e32b0a", "d8f1a83371487d611ce704e0a6731f97a933c43569690022fce33cb5aecdc0a7"), TestFixture(16, "e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df", "55b59eb434dd1ba3723ee0dc72", "fb3e3d1b6394d2daebf121f8ac", "c64ab507e12e436ac943eb0090270758ab09f93fa3ba7d7a2aa8eac789", "05c57aab99f94b315cf8bdd2d6b54440c097fe33c62a96b98b1568cdee4ce62c"), TestFixture(16, "e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df", "55b59eb434dd1ba3723ee0dc72", "549ba26a299391538b56ce4bd7", "69ef2a76ab2900e3a9e404b3eb2293813f1bcb96564f772e9308e42b2d", "1c1b0933c508c6a8a20846ebd0d0377e24f4abc0c900d3a92bc409ba14ef1434"), TestFixture(16, "e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df", "55b59eb434dd1ba3723ee0dc72", "287f31e69880823df7798c7970", "150bb9fa1a3a138dd5cb46814c81877380d5cf097c2fb5177750f8b53a", "9f5cf9149f556124d6bb4e3e243cca1502c02682709392cc2ec7eb262fd4d479"), TestFixture(16, "e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df", "55b59eb434dd1ba3723ee0dc72", "040d18b128ae4a1935f9509266", "397990adaa14dba9174b9a6a5acf42c75787edc62a180568c6ef56545d", "1a49aaea6fc6fae01a57d2fc207ef9f623dfd0bc2cf736c4a70aaaa0af5dafd3"), TestFixture(16, "e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df", "55b59eb434dd1ba3723ee0dc72", "92441cbe8d70820870bb01ad63", "af3094a20fca13b85209cb555f56d47a0631f2038103e3904b556ba7a5", "f29a0b2c602ff2cacb587292db301182e6c76c5110b97ca8b706198f0e1dbc26"), TestFixture(16, "e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df", "55b59eb434dd1ba3723ee0dc72", "f11d814df217de96333dee1cbf", "cc69095170ad4f26118f24e4835be15b7ae24edccd0b0934e3af513ed3", "01fcf5fef50e36175b0510874ea50a4d2005ad5e40e5889b61417700d827251e"), TestFixture(16, "3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0", "61bf06b9fa5a450d094f3ddcb5", "959403e0771c21a416bd03f38983", "37a346bc4909965c5497838251826385a52c68914e9d1f63fd297ee6e7ed", "0245484bcd987787fe97fda6c8ffb6e7058d7b8f7064f27514afaac4048767fd"), TestFixture(16, "3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0", "61bf06b9fa5a450d094f3ddcb5", "23fe445efa5bcb318cc85e2ad1ac", "81c90102c44e7cc9cee2de5b09ad364b603de6afbc2d96d00510894ccbe7", "52f6a10a022e5ee57eda3fcf53dcf0d922e9a3785b39fad9498327744f2852e4"), TestFixture(16, "3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0", "61bf06b9fa5a450d094f3ddcb5", "762fdc3e0c30c7ecf2ec8808bb79", "d418996232257014b0c6087963781a4321c2ddbc35ce4864457d611219e9", "d236e3841b9556b32dbd02886724d053a9b8488c5ad1b466b06482a62b79ebb6"), TestFixture(16, "3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0", "61bf06b9fa5a450d094f3ddcb5", "b6813d5fe8afa68d646c197337a2", "14b67803d6ba117526469902efa3296e55efebb17fe145cdca9b31ea7bcc", "0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e"), TestFixture(16, "3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0", "61bf06b9fa5a450d094f3ddcb5", "4ce8b6578537215224eb9398c011", "eedff30bbb2296aa66c113e9181059270a0510e7cc1b599705853af2144d", "7f291aa463c4babc76b4a6faf2e27e9401586b1ac83e4b06a4090e94b3ef5fd4"), TestFixture(16, "3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0", "61bf06b9fa5a450d094f3ddcb5", "9ebf93643854ea5c97a4f38f50bd", "3c88d63806415da4d58e73fe88bcb55847573bf21e946ce9bdc5f569e3ff", "06bca7ef6f91355d19f90bf25590a44a24e5a782f92bc693c031e6de1e948008"), TestFixture(16, "3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0", "61bf06b9fa5a450d094f3ddcb5", "da989cc7d375ed5fac4d7f938d74", "78afd99bed605aa7ee67ffe25575b8a61c5687ea02f0276824b8316b76f1", "5a44ff94f817c7c028a8f3db35a4d01364d2598432469f09ded86e5127d42d35"), TestFixture(16, "3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0", "61bf06b9fa5a450d094f3ddcb5", "6fbab5a0f98e21e4d15904af5948", "cd8df0fcc79b961c937384de8149a07ee02791011129fcacffcfb1bf4145", "2a755e362373ef27a911c4d93ca07bc97135645442ad7ad6a8ef98146c71e9d7"), TestFixture(16, "3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0", "61bf06b9fa5a450d094f3ddcb5", "b610349e8b370a7c195598573637", "142771c2b522bd845b7f1826ee36d34204b1ce23f5f58a8eb7cf1fa8cfa7", "f7988873f45a5de314e5381d3f14d8f8c48c9b649bf3e745ed5dc882d507da58"), TestFixture(16, "3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0", "61bf06b9fa5a450d094f3ddcb5", "1d969fd81dab5ced3e6ee70be3bf", "bfa1da8423beeb157c44677a3bbe9c618bb88bbcefb008a5ea6bed4ff949", "95d2c8502e28ab3ee2cac52e975c3e7bccb1a93acc33d9c32786f66d6268d198"), TestFixture(16, "fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a", "a5c1b146c82c34b2e6ebeceb58", "54be71705e453177b53c92bbf2ab13", "788db949697b8cd9abbc74ed9aa40cd6852dc829469368491149d6bb140071", "5e60b02b26e2d5f752eb55ea5f50bb354a6f01b800cea5c815ff0030b8c7d475"), TestFixture(16, "fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a", "a5c1b146c82c34b2e6ebeceb58", "22197f9ad14591e7a6d5f8b18c969a", "0e2ab7a3e67b2c49b8551ee7e4998556940dc5a7e44bf10234806d00a012b5", "210c04632341fbfc185bfe3cbf6fe272bbe971104173bcb11419b35ab3aaf200"), TestFixture(16, "fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a", "a5c1b146c82c34b2e6ebeceb58", "096b2f530933c1273304a6ad423726", "2558e76a3e0d7c892d8440fb2a38390898f7dbde25b0b70d335df71a06987b", "d3a205dd017e79a67400a937a20ef049f4c40d73311731f03ab857a3f93bd458"), TestFixture(16, "fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a", "a5c1b146c82c34b2e6ebeceb58", "d44fdfd9da3a63c1083afe574e91bf", "f87c17e0ed04de6f16ba1801269ea02fd10d1f21b6b963c05aeda8eb09e272", "0c9b3ba4faf5fc2f310ad1bab06c4ca13474b714feeffb6ad615c1b850bbd6a3"), TestFixture(16, "fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a", "a5c1b146c82c34b2e6ebeceb58", "8d836acc13ed83c2b2c706415c9679", "a1b0a2f524d33e6cac47e0173499664491d23d90ff55abca17e9d943b98c7f", "d9bb71ad90152d5c1af358c8501fa89ebd4b17bf4ff43841528cccb79fd791b3"), TestFixture(16, "fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a", "a5c1b146c82c34b2e6ebeceb58", "2a68e3fe746f593c1b97cb637079c3", "065b2bc74351e49205172d351876dc9616886c6b2adc97db5a673846b6662c", "69dc21eb6f295b12ba493ee8fe6c40d78af946067ce772db316a3cbf00d3c521"), TestFixture(16, "fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a", "a5c1b146c82c34b2e6ebeceb58", "39799b001ed2c334c269acb0f2328c", "154a533929ec7e9adce94ae69a3d932441dcae1760db90379bd354fa99164e", "095eb52135dc6d9c1f56a2571c1389852482e7aa3edc245a3904a0449db24a70"), TestFixture(16, "fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a", "a5c1b146c82c34b2e6ebeceb58", "42143a2b9e1d0b354df3264d08f7b6", "6e27f212a923b69b5373c01b60f8a9c7c7deb28bdcf84886ef843216b94449", "efd7270e0396392fde8b0ddaab00544cbbd504f4d97d4e90d749d1946de90dcb"), TestFixture(16, "fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a", "a5c1b146c82c34b2e6ebeceb58", "a3dcf26327059a4245b79a38bb8db6", "8fef3a5a103b27ec5b377c6ed382a935061ae3cd892ba63c44b809d6d29421", "8bc181ce2e66294e803a8dc3834958b5f173bc2123c0726e31f3fca25b622ed6"), TestFixture(16, "fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a", "a5c1b146c82c34b2e6ebeceb58", "3d54883449ecca8f153436c25a0a01", "1167400d7ed277210bb4d09432051e3c9ae69a4c59ff8e251c2fe022d065a9", "c39ec70c2c71633ae0dccc41477ac32e47638c885cf59f34ebd4a096d32f91f9"), TestFixture(16, "ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62", "121642c4218b391c98e6269c8a", "d15f98f2c6d670f55c78a06648332bc9", "cc17bf8794c843457d899391898ed22a6f9d28fcb64234e1cd793c4144f1da50", "718d13e47522ac4cdf3f828063980b6d452fcdcd6e1a1904bf87f548a5fd5a05"), TestFixture(16, "ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62", "121642c4218b391c98e6269c8a", "60d55a8d5ab591a51e87fdf6aaa2ad25", "7d9d7df808aba2153f76ce016b1f54c68b55bbe42d8c97504b97c34a5f16e6a6", "a371ca29b92ed676bab5dfc4d78631bb6d9bb23a29f822907084a1f0fe17721f"), TestFixture(16, "ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62", "121642c4218b391c98e6269c8a", "cbf112e4fb85276c4e09649f3de225b2", "d6b93591a99b14dc6ff85768fc5fdc51017d8706acd676ae99e93d5312a4113c", "01ec87920b42639d4ba22adb1fbe5138d2849db670a2960fd94a399c1532ed75"), TestFixture(16, "ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62", "121642c4218b391c98e6269c8a", "865b89aa38ee1b5a3ce56620307e8937", "9b13aedf6af028ea1d1455d7f1c370d45982f0fe5d951a8c62c87894657301e4", "eebd2bbf1e9f6d817cd8062a6a9680e7f10464eefeb50b07cb46b14b9b3fcb2c"), TestFixture(16, "ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62", "121642c4218b391c98e6269c8a", "a8efc37d1b8b51f2a47b21dd14da383d", "b5a7e40849956242858a122ad567c1de5addfddbb59f4985947fb3a9ab56333e", "72863362612f146699f6b2f6ec3688f2ca6cb1505af7a309c91c1933e34d516a"), TestFixture(16, "ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62", "121642c4218b391c98e6269c8a", "d9b0eaaff786165f882f41a98dbc0c35", "c4f8cddaa59825efa9de725e4c01f5d6b651053516673402a57538db1a9ce7e9", "9c9efc6593f96207678db813608f2b8bc33ed1bef974ed77ed7b6e74b621b819"), TestFixture(16, "ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62", "121642c4218b391c98e6269c8a", "df49d972b6ebbbb18ee975ac635d847e", "c201fe07e4f58801af18465ba2e07d9d86d772b1a1991b7be6589bbccad36171", "dc482a051b58d8a3904d3af37c37b51983f634a504451bbba6f77d71337f8e78"), TestFixture(16, "ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62", "121642c4218b391c98e6269c8a", "78318aa5cd16699b77bdcea2fc9d1d20", "6579add09f085a2b564cfd553d20e4c3569387a1a6bcc826e94012670820576e", "51ef065a43caa23faf750b02a41ad6ba701aeb8058f6d8738d6f6b005bec7f60"), TestFixture(16, "ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62", "121642c4218b391c98e6269c8a", "8e20d65d02dd9a64379f75b6d8328f2d", "9368f12850c3a9d4166e4641198f76cee9c788b4aae9b2c6caf0c44aa9bd2ed0", "88e2a74d2920c89c6a101f5f06d0624a6d5eabd9bdb51395ee3983934c55c73d"), TestFixture(16, "ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62", "121642c4218b391c98e6269c8a", "97e8d8513af41b97801de98cc4269096", "8aa0ff2468ea2827a1ecda7b059b6975f1df0f01944641a1b04d753e6ab8d3cc", "ada3ed7db2dabbfbc441ef68a5656e628d6d5bd6c1574369688497179a77601a"), TestFixture(16, "7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d", "98a32d7fe606583e2906420297", "b0053d1f490809794250d856062d0aaa92", "a6341ee3d60eb34a8a8bc2806d50dd57a3f628ee49a8c2005c7d07d354bf80994d", "217d130408a738e6a833931e69f8696960c817407301560bbe5fbd92361488b4"), TestFixture(16, "7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d", "98a32d7fe606583e2906420297", "51eb190c6a9f46e8ec1628b090795470c0", "47da3af0f599fcdb24cd3266fb04838df13c1c5755a5a240c33b2b890a486aac8b", "4ae414bc888a42141d3060c71c2dbbffd425b6a952806982271a8e756b3c9e24"), TestFixture(16, "7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d", "98a32d7fe606583e2906420297", "25144e807e389bb0e45b6dc25558caf61a", "33256d7ce13e21832c8077143e251d0b2b4cfca1c19abf447d7bc0898d61885144", "7b7f78ae1a5ee96fdc49dacd71be1a6ac09a6a162d44dea0172886eca5674e46"), TestFixture(16, "7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d", "98a32d7fe606583e2906420297", "dbe1ee14abfe2ecf4edf6db206cf9886ce", "cdd0cde834f894fc860477646db24f7bff229cc7a390867a245dcb7c434f1db347", "03f31c6143b77f6ad44749e2256306b8bf82242f2821fad4075b09b388ba81ca"), TestFixture(16, "7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d", "98a32d7fe606583e2906420297", "db6df31f12bf552f81deff5fa2a373fc22", "cd5cd0e38db9ef1c4905e589c9dea401135361b539f9fe0fb7842907c2326aef63", "030390adb572f2bd2a6a4454fd68236cd1d465574328aa001d553375cc63f8a2"), TestFixture(16, "7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d", "98a32d7fe606583e2906420297", "ff2a97b49fcc6a50d4549c979d53ccc51f", "e91bb44800cad0631c8f8641f62e1b382e8ed10943929e7d7bf798b2ae8371aae5", "7294ae94358669f2ada4b64c125b248df7fe86c6715e3b6a7b9bb2bd99392c8a"), TestFixture(16, "7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d", "98a32d7fe606583e2906420297", "73ddfa0185200a890b7690a7e3986d8818", "65ecd9fd1a26b0bac3ad8a7188e5ba7529f92b9e49ab83f113f8949dc9e4a36e0d", "4d1513478fc1fb0a18eb6d2a9324fefbd975ecd1b409025de826bc397462acc1"), TestFixture(16, "7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d", "98a32d7fe606583e2906420297", "5c7604f9ac8fdf30ee5820e5aeb75b65d7", "4a4727053389650326833a33c5ca8c98e6d0e53223adff22a08e3dddf66fff23e3", "b26a7ff61bfe94864249af7cc9b4a723627dd4463f5a22f0ca6063769522eab7"), TestFixture(16, "7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d", "98a32d7fe606583e2906420297", "d44fdfd9da3a63c1083afe574e91bf01c9", "c27efc25453cd9f2c0e1e48125ec68fcf833f49a42521a7a2367f91bfcc2180b7c", "960f9a85cfbfb6eab223a4139c72ce926a680ea8e8ecc3088cf123de659ad310"), TestFixture(16, "7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d", "98a32d7fe606583e2906420297", "bb515dc227abb9acad8fefaa14771bb77b", "ad607e3eb8ad039f6554f57c7f0acc4a4ac08bd395c6807223311070659f550934", "3718467effb5d5dc009aaefce84d8cb4fe8f80eb608f4c678f5d0de02ea11e59"), TestFixture(16, "0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c", "f61ef1c8c10a863efeb4a1de86", "6a26677836d65bd0d35a027d278b2534e7df", "d1c1f3c60603359c7d6a707f05ecb2296f8e52f2210b7a798ad5c778ee7cfd7fe6e0", "67874c808600a27fcab34d6f69cc5c730831ad4589075dd82479823cb9b41dc3"), TestFixture(16, "0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c", "f61ef1c8c10a863efeb4a1de86", "4021ff104ff1dbd91e46db249fd82198b0a1", "fbc66bae7f24b595b076a926bdbfb68538f00923bb5a347af13df12f234fca5f03ef", "e0c27cddf919d3092d9a34766c89a5ae6dcf39fe954d1e6f1a70ddf96805def4"), TestFixture(16, "0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c", "f61ef1c8c10a863efeb4a1de86", "6a681f164efce199a787bccff223b8ae1a98", "d18f8ba87e298fd509b7cecdd0442fb392c9d03ed7bffac83e890caceb6903d9cab5", "7ae9eca03f616ab39ebb3be26b848842b4aa584e5c8e5695065ad5af34951175"), TestFixture(16, "0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c", "f61ef1c8c10a863efeb4a1de86", "7861dac338ba3f8274dca04c8c6f92b6d44c", "c3864e7d086f51cedaecd24eae0805ab5c1d4dd8f30870025b2bd1e2a2511574d3e7", "b47c9bc4eb01c74f5db2e6a293bef80db18c58cf06feef7ee0f8a7a9a51c22bb"), TestFixture(16, "0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c", "f61ef1c8c10a863efeb4a1de86", "a3f0473c620d2739d5ba4f7156f88d0fb669", "1817d38252d849757b8a3d73749f1a123e386046d17f337f3cb49884d94995edbdc9", "f6afd661f218c7426b92ee53e65d14898cd0c78a7e594fcc6ac0e3fb5cab1c9c"), TestFixture(16, "0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c", "f61ef1c8c10a863efeb4a1de86", "07c535d9456a6ff1e41321150d16dae3f7a3", "bc22a16775bf01bd4a2353172f714dfe7ff25fdc77b43bca254d6459263cdfed8fbb", "d3802911e341577046cfc61d9043b4af059fb4bef3c6a2ff46ccdcb05670af37"), TestFixture(16, "0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c", "f61ef1c8c10a863efeb4a1de86", "5ee220720a896249efdab2ce418318bb5ebf", "e505b4cc3a5c0c0541eac0cc63e48fa6d6eedd1a1d36c8164c55d55dbf0ff1e9517a", "db60720db67a60ca286fe744d46173c231fbcc7deb4c9b0d87d52a2247e06b74"), TestFixture(16, "0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c", "f61ef1c8c10a863efeb4a1de86", "98e4eb0361c8bf40bcbe0539b0850e4c35ff", "23037fbd511dd10c128e773b92e29951bdaeb476e2ca48fd52bec0539b00744a8a07", "57f70ba5493265b30491decc726354e2065e7971a2efd56db9cf0f79b1d76859"), TestFixture(16, "0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c", "f61ef1c8c10a863efeb4a1de86", "7f0745bea62479c0080ecec52e37c1e32d72", "c4e0d10096f1178ca63ebcc70c5056fea523fad68c62b81d62f2d490ae74f5bb1465", "4a29b9ad548964942f87f28ba267ec0d0e8f72c73b3823ee57693dd63c2605c1"), TestFixture(16, "0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c", "f61ef1c8c10a863efeb4a1de86", "e99ed2ac6c38e033061b5d85f3e77dd72518", "527946125ced8e7fa82b2f87d180eacaad4913b15d8000266c61ba5aec898eb35b52", "acbd2e9911b3218a230d9db5086d91dccac3fc93fc64b0f4a15d56954906b2b7"), TestFixture(16, "bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f", "05b50c458adbba16c55fcc454d", "c1a994dc198f5676ea85801cd27cc8f47267ec", "7c9b138177590edaafec4728c4663e77458ffbe3243faec177de4a2e4a293952073e43", "89ad6ae1e550975eaa916a62615e6b6a66366a17a7e06380a95ea5cdcc1d3302"), TestFixture(16, "bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f", "05b50c458adbba16c55fcc454d", "791e232bfb42fb18197adc1967da1a83f70168", "c42ca4769594a3b45c131b2d71c0ec00c0e97f8422f736fc435687634d42254b22fd99", "dfddb719d00398bf48a6cefd27736389e654a93b8595cd5ac446af1996e0f161"), TestFixture(16, "bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f", "05b50c458adbba16c55fcc454d", "3d4127942459bb8682e662dfc862467582fa68", "8073a0c94a8fe32ac78fa5ebde78b0f6b5127f38a96e68ef7dbaef1b460cc0980eacd4", "58ef310997dcaf067dd217274921504da6dbf0428a2b48a65fe8a02c616ac306"), TestFixture(16, "bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f", "05b50c458adbba16c55fcc454d", "0e71863c2962244c7d1a28fc755f0c73e5cbd6", "b343016147b47ce03873efc86345faf0d223c15c5c702a82d468929227502e4e35796f", "511e5d5e100b595f6b20e791830bca37e23f7b785e482a58405bffe7a632a5b8"), TestFixture(16, "bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f", "05b50c458adbba16c55fcc454d", "e0f1cd013e6aea4fa484fc3fa35d348b1a2399", "5dc34a5c50bcb2e3e1ed3b0bb547c2082dcb8e89188c0940182dd99a902d158c5b0810", "e48dfaa53b6807ea6f01d8dca67960b9f321f7851f324459a9bf61fe0be73abb"), TestFixture(16, "bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f", "05b50c458adbba16c55fcc454d", "b1cc1946b4fc1dbd033254cdf536f61e9f9cd7", "0cfe9e1bda2a4511465b93f9e32c009da874c015849acbb7af1892790300bb84fb0558", "c12c0423fe36e4c88775dd00b4af267b85b7dd2a37a742a3156923c8917c97a3"), TestFixture(16, "bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f", "05b50c458adbba16c55fcc454d", "87284658928208e3bddca83e3ceb13708d88d4", "3a1ac105fc54504ff8b56f0a2af1e5f3ba60c3e75aaf3077ac6dfb5454851ec3910de6", "4255f8af18df7237e0abe98421aec9634443561752d893aaffe76380e829ef32"), TestFixture(16, "bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f", "05b50c458adbba16c55fcc454d", "bdb79f931ef3035a33bdd1b032fd9de8f6b2ba", "008518ce70255bf676d4168424e76b6bc15aade70f42e3e1f2b5bb58433bd11f5dea1f", "ab83567833d2f3461b5fbecc0e366694bb5ea00933b2b3e792ec3aefe20325df"), TestFixture(16, "bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f", "05b50c458adbba16c55fcc454d", "1f9c3a8eb8bc59f3869e10f73883aa8f8990cb", "a2aebdd3d66a015fc3f7d7c32e995c0cbe78dc564f6248cefe5fc7cfb547c90a558925", "bd1446ba3185d1c16551730947c22142142caa8cc1c540e89ab734ec297401bc"), TestFixture(16, "bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f", "05b50c458adbba16c55fcc454d", "5f28809181f9a889894da8d6fe1fde6cce354a", "e21a07ccef2ff025cc246fe2e80528eff9dd5db52249d812f7f235afa0732e984e91b2", "b87577755d2d9489194f6f7cfabf267dc3433a9c91954e81beb72c5e06870922"), TestFixture(16, "8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876", "8479bdfad28ebe781e9c01a3f6", "7b125c3b9612a8b554913d0384f4795c90cd387c", "6cc611d816b18c6847b348e46a4119465104254a04e2dfeeeac9c3255f6227704848d5b2", "7aebdfd955d6e8a19a701d387447a4bdd59a9382156ab0c0dcd37b89419d6eff"), TestFixture(16, "8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876", "8479bdfad28ebe781e9c01a3f6", "8b013f5782d5d1af8dbd451a4202866095dac975", "9cd572b40276f5729e9f30fdacb7e67a5413d44338d48329997c5981d678b5e24a6f01b0", "d119f300fbd74e754a200ea2c3f9fabc1466d02078c84245db693eef3f5672a6"), TestFixture(16, "8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876", "8479bdfad28ebe781e9c01a3f6", "b2b1d82a5523b72ea366a680922ed3a4624536c4", "a56595c9d58093f3b044d3677c9bb3bea38c2bf2a77e3ab68e0a73519591a33ed098b758", "d6204303b86acf62d5ab860ca70161288ede56e3cf017c08dca56fd2d6f8f6fe"), TestFixture(16, "8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876", "8479bdfad28ebe781e9c01a3f6", "f8c4eb4285d3d7744da52775bb44ca436a3154f7", "ef10a6a10570f3a95e87529255f1aa59abf849c1cff6c24251c2fb7b8604dfa10c60ef4a", "8557e22eb4529b43f16b1f8ae47c714ac8a2c827c1408a47704778b4c5b52601"), TestFixture(16, "8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876", "8479bdfad28ebe781e9c01a3f6", "6e7fe35fa39c937a0e6b3a8c072e218650f42b8d", "79abaebc233fb7a71d494f6be99b419c913d36bb6c3c39f915d081d34559179869b32d81", "8c1a4187efbb3d38332f608f2c8bbe64247d9afa2281ced56c586ecb4ab7a85e"), TestFixture(16, "8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876", "8479bdfad28ebe781e9c01a3f6", "917b467d841850fc6e648f1bc298a7f9f1ee38ca", "86af0b9e04bb74217d46fafc2c2dc7e3302725fc9389a6a6a74c6eb0e1f87562469f2082", "a41bb1f256228302cd0548ae2148ff42774d18c2d6d3e38b36bc4938da13bac3"), TestFixture(16, "8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876", "8479bdfad28ebe781e9c01a3f6", "2b4314fe1a6bfa786b7cfc13fbee861b348efbf6", "3c97591d9ac8dea5785e89f4155be601f547e6c03bed3a2f5dfdbfcc0d7ac26c88d1962c", "b0b024e20c4f75a6dad54c21a9edbce846792e957878b1c8ed2d916c757e2b3c"), TestFixture(16, "8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876", "8479bdfad28ebe781e9c01a3f6", "e19fa7f83c79920cbff45c41a9dee8fc99e97396", "f64bea1bbcdab6d1acd629a6476b88e658206ea035ea1d99be344fa1467ee91c73bbca67", "42153925c46fc9d5d328312d62f59bb99fdc4ac479a3386d5f88fefd4b32f577"), TestFixture(16, "8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876", "8479bdfad28ebe781e9c01a3f6", "53e0475cf492b3d39dad600f5c58eb0bd0021554", "44340abf7431970e8e8f15e8b2ed8b1111cb08627936ec10a81b36768b606e9a38b2f4c5", "37ab2a0b7b69942278e21032fc83eba6cdc34f5285a8b711a08da6acd42299fe"), TestFixture(16, "8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876", "8479bdfad28ebe781e9c01a3f6", "c119a383d9a3d4bff4270a1d22076b346db5f61c", "d6cdee605900f062e7057ffaccb20b2eac7ceb2a11575ae03ea8a57bbe4a67c060367b74", "4a17522da707b4b2587a0ae367a2cd2831bb593a18ef442a7977eda6de045878"), TestFixture(16, "c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2", "94ab51ce75db8b046d6ab92830", "73b09d18554471309141aa33b687f9248b50fe3154", "b7e8264ca70fd2a4fb76f20a8ad5da3c37f5893fb12abeeaef1187f815ca481ed8ddd3dd37", "2a243246bfe5b5ab05f51bf5f401af52d5bbaa2549cf57a18e197597fe15dd8c"), TestFixture(16, "c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2", "94ab51ce75db8b046d6ab92830", "b64d00f3a4df754fa4ee6376922fb67ccce0c6209f", "7215bba75694d6dbced93b4fae7d95647045b12e7accc2b55011dbe92ce7619e0ad48b4ccf", "0595306eb7441622a49800edee0134492d82320707fceba902af2e0c95fe634a"), TestFixture(16, "c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2", "94ab51ce75db8b046d6ab92830", "2b11d1ac74ffe701ec733d32085b1054132726e622", "ef496af886b444958644650b3409334caf8251e8c71e8b1f4d70d8f4c7df4f22847d36b394", "bd439dbefec589e120fb4f9825b315bf86523b85c61791cd4da4c8d474ba2714"), TestFixture(16, "c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2", "94ab51ce75db8b046d6ab92830", "a88f22424643a523aa3d7d88f4364f1290f49dd0a2", "6cd79916b40806b7c00a25b1c8646c0a2c51eade47a85e76a9d07b7b361ca56d53c34cda50", "cfebe1cf82267394065bcecfada6709c6c35a3ac835644f560d4c9a8c1848364"), TestFixture(16, "c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2", "94ab51ce75db8b046d6ab92830", "c81427bc84c6a3cfefd4c4cb210fe82212977e1947", "0c4c9ce8768d005b85e39cf21d5dcb3aae320917a2fddb010e7508ad03ad287068ecee6020", "7a37255b682766a0bfecf78e5162528885a339174c2a49325739d2bd8877e64f"), TestFixture(16, "c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2", "94ab51ce75db8b046d6ab92830", "28c4d6de3e2ce51b849b135d9cfd3084f0e3155447", "ec9c6d8acc67468feeac4b64a0af139c4c46625aa2ddea785e6c470c52c4fdf432fd78b66e", "619f2ae80070e278615466a3fd6c9acb7b510c5679bed7038889c77e78d8bd32"), TestFixture(16, "c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2", "94ab51ce75db8b046d6ab92830", "4c88151cafef75832bacef43a06e862349d56b67ee", "88d0ae485da4d617419bb77a9c3ca53bf5701c690b91232cfbd7ffff252498b35274fb2995", "b2571e56f66a857daffbdc99370ceddd4a7bed3867d600cc797000a3b7b57a9d"), TestFixture(16, "c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2", "94ab51ce75db8b046d6ab92830", "572855e22ce89bc2bcf09cb15a1765d99973449d61", "9370eeb6dea33856d6c7c488664546c125d633938472b2c50e5e391ad104f9ee33b94f2872", "db409636e3e3bcd606a91aeb7592009896f9ad2c4cc6b7f578e6ad59c0f8fa22"), TestFixture(16, "c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2", "94ab51ce75db8b046d6ab92830", "89ce46b3de3afaf2518d419b1a2ac24cabca269a96", "4d96fde72c7159663bba19a22678e154176f5194732d69c5d6db1b130102af3dae0690673b", "62c89a835721207a182968c516dc8be45774ec846e8dcab9ab8611888f2a76a8"), TestFixture(16, "c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2", "94ab51ce75db8b046d6ab92830", "edf1682a626e9fbf3d57bb260e0876c6f92ba5b114", "29a9d37e90253c2b5760e31f325a55de458ed2bff1489903365970c2673c9fd457e1077aad", "33f30ddd83002eea50fd4a8fae39d0980a04160a22ac88b755ac050f1d1f8639"), TestFixture(16, "9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4", "af1a97d43151f5ea9c48ad36a3", "3cbb08f133270e4454bcaaa0f20f6d63c38b6572e766", "3966930a2ae8fdd8f40e7007f3fde0bd6eb48a46e6d26eef83da9f6384b1a2bda10790dadb3f", "f5353fb6bfc8f09d556158132d6cbb97d9045eacdc71f782bcef62d258b1950a"), TestFixture(16, "9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4", "af1a97d43151f5ea9c48ad36a3", "946e86795c332031e2d1ee09d3d4a101fb6800d00911", "91b31d8245fcd3ad426334aed2262cdf5657efe408a5587bdd120a7d08cd3841cb117af444fb", "e3a1555ffe5f34bb43c4a2dae9019b19f1e44a45fb577d495d2a57097612448d"), TestFixture(16, "9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4", "af1a97d43151f5ea9c48ad36a3", "b76ce2ab0065ba1c0a754494991c8c452cb416f18ab1", "b2b1795019aa4980aac79e3398ee019b818bf9c58b0545b32f81dcf03e2bcc2aaf62ad366e97", "9c5d43c1a1269cde199509a1eff67cc83a1759b71c9e7a6ee99f76b98c6e23a6"), TestFixture(16, "9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4", "af1a97d43151f5ea9c48ad36a3", "a3e0d8d0784155bfc45769c52711d4fa68e8bc390c20", "a63d432b618ea62364e5b36226e35924c5d7530d0d94fea17d78533bc9e022dbfb460afdf499", "b07452a7900a289b91b2771dfdd5108852536659aa259def7b41e38f80bd03ab"), TestFixture(16, "9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4", "af1a97d43151f5ea9c48ad36a3", "6e6a88abbb52a709b47365ad6aa8016fa9a03a9bd834", "6bb71350a29d549514c1bf0a6b5a8cb1049fd5afd98056defc6dcaeec80b1c639350ab6f1fde", "6b30f55c3101540523a92380390f3f84632f42962061b2724cde78ac39809397"), TestFixture(16, "9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4", "af1a97d43151f5ea9c48ad36a3", "eba1810d537041821121aeff8e0914ac26a550072c8c", "ee7c1af64abfb21eb19374588ffb99728b9abf332d389d37b7251fb8c0ef2b37c36d51219d0f", "9fc62d14f8b7a6026509275cff80312ff1ade2b5d9c274cb72a506a571439fc1"), TestFixture(16, "9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4", "af1a97d43151f5ea9c48ad36a3", "dfc6692cd2442e5ff1f918c8812a27f81d107d16a12f", "da1bf2d7cb8bddc3514bc26f80d8aa26b02f9222a09bd279d9da4437c8a2a252436508134c56", "6b9389cc42113d639fd2b40cbc732ae0dc7c14513b88b36b45a6ea5a06fe4d2b"), TestFixture(16, "9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4", "af1a97d43151f5ea9c48ad36a3", "9ad338cbfd1b52e6ae4178f05e00062274f8b0b25eae", "9f0ea330e4d4a17a0ef3a2575ff28bfcd9c75f865f1a63943543bc1c5f5991ecc5964a288f79", "db72d98d63fc10acff7dceec0e2691a80ecee50a0e957ad166c77952a50318bd"), TestFixture(16, "9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4", "af1a97d43151f5ea9c48ad36a3", "9f5a05db89e0e336da066ce81b79ad9be1d0ec4fb7b8", "9a879e20902f10aa7ab4b64f1a8b20454cef037bb60c0a49ee2b7ceddcbd28abb24b77d5edee", "e98b710c47a4d12a73cd8aa2613fc2910c16f4195ea7f15650132493521d19be"), TestFixture(16, "9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4", "af1a97d43151f5ea9c48ad36a3", "58f31e5770070a5d4031fb795dc2d298561d3559960d", "5d2e85ac69c8f9c1e08321de5c305f46fb22da6d97b9b099a68cfa3572d974e03232e09f37fb", "527817316fc48b105f8ab178dd2db1fefa09c50461aa9d8bdf3c03482343bbf9"), TestFixture(16, "d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135", "3891e308b9f44c5b5a8b59004a", "79ac1a6a9eca5e07ce635bfd666ef72b16f3f2e140d56c", "1abcc9b1649deaa0bfa7dcd23508282d9c50ca7fee72486950608d7bcb39dcf03a2cab01587f61", "0cda000ed754456a844c9ed61843deea9dadf5e723ea1448057712996d660f8c"), TestFixture(16, "d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135", "3891e308b9f44c5b5a8b59004a", "76d12e3c4c5d990bf563c60aa4999e52998d887f97477f", "15c1fde7b60a2dac84a74125f7ff4154132eb0e139e05b1c4fb40e5c8bc37152a173d4bbb18c3e", "3fb6ddb76809b8e6d703347664ef00a365955124c603900d5c8d4ff476138252"), TestFixture(16, "d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135", "3891e308b9f44c5b5a8b59004a", "a027c28fbe22111fd4c8a226cfe8531c16d7790d561eca", "c33711544475a5b8a50c25099c8e8c1a9c744193f8b9ee019c359008adae3070b5a543ead0effb", "d9fc295082e8f48569eb073ac1b9566246728fc62ccaab4a5667c472c98b2626"), TestFixture(16, "d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135", "3891e308b9f44c5b5a8b59004a", "fa597e37c26c38694abdcf450f9edc529160fa0d651979", "9949adec383b8cce3b79486a5cf803541bc3c293cbbe5dbd099ab134756b90746762a92a4a9f7f", "7a459aadb48f1a528edae71fcf698b84ed64dc0e18cc23f27ab47eeabeaf833f"), TestFixture(16, "d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135", "3891e308b9f44c5b5a8b59004a", "9e4c8aa9b58a8eabc5586892f5541000b43f17d9a051a0", "fd5c59724fdd3a0cb49cefbda632cf063e9c2f470ef684fa4f6adfec85d055310107ba89198afa", "484207909dec4c35929ebe82fcacf20d2af6d850bd69364ebac9557adeadfbd4"), TestFixture(16, "d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135", "3891e308b9f44c5b5a8b59004a", "7d9582cf9e3bb9ee34dce965f56b08e716589486b0641c", "1e855114646c0d4945186e4aa60dd7e19cfbac181ec338915d23eb2e952afcc89fbddb567d9d75", "88b5448372548e6aab1b262630a28a471d285514703f1bdb10c695850e18fe6d"), TestFixture(16, "d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135", "3891e308b9f44c5b5a8b59004a", "5a387e7cc22491fc556fe6a0c060b4911d01f0c11f801e", "3928ada73873255b24ab618f93066b9797a2c85fb1273aaad6c31828314e24198f005955ca8f5e", "0e71863c2962244c7d1a28fc755f0c73e5cbd630a8dbdeb38842d7795d830d2e"), TestFixture(16, "d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135", "3891e308b9f44c5b5a8b59004a", "87946e910059cbaf48df63b220f397049c65ca10cd1920", "e484bd4afa0e7f08391be49d7395480216c6f28e63be04e531ebbadccfe47182b41904bbfebcfe", "2aa7a28da38c42fda2e578d9d6340cd8e80b9b32047c3db296d0640d517b0872"), TestFixture(16, "d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135", "3891e308b9f44c5b5a8b59004a", "c62f67d208f1c8ffd5d57df9de15ef54f97fbc07d1630a", "a53fb409f2a67c58a411fad68d73305273dc84997fc42e7c582414154236c09ee704cf4a5de411", "3382051c268891da04e6ca73adcead4029f6a1593be4acfe3968e7351a6a2fb5"), TestFixture(16, "d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135", "3891e308b9f44c5b5a8b59004a", "697e73eaaf562d31bdbf7ce9e78c7426fe1c87e421def9", "0a6ea03155019996cc7bfbc6b4eaab2074bfbf7a8f79dd57c9990029c89d1b37988745fa5737a3", "c352828b1920e53bbb60f2ea6a5f15639659e6f3243405c26f6e48628d5519a9"), TestFixture(16, "4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976", "00d772b07788536b688ff2b84a", "9cea3b061e5c402d48497ea4948d75b8af7746d4e570c848", "f28ec535c2d834963c85814ec4173c0b8983dff8dc4a2d4e0f73bfb28ad42aa8f75f549a93594dd4", "5f8b1400920891e8057639618183c9c847821c1aae79f2a90d75f114db21e975"), TestFixture(16, "4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976", "00d772b07788536b688ff2b84a", "2b223932fb2fd8433e4b1af9e8234a824569a141f6c96a69", "4546c70127abacf84a87e513b8b90331639d386dcff38f6f4de907a59c5e4d3f21e1348d7cdf92b6", "1ae8108f216defea65d9426da8f8746a3ae408e563d62203063d49bf7e0d6bdf"), TestFixture(16, "4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976", "00d772b07788536b688ff2b84a", "4d57cbe4a7e780d4ed17267d5ebc91750c2f0209e0444bd2", "233335d77b63f46f99dbd9970e26d8c62adb9b25d97eaed4ff4239544e2f354d6c6837cd9c23b884", "460f08114b1015fe8b7a9b5dd1b9e6a3d28367c4bd15f29b13c02a8cb9a53968"), TestFixture(16, "4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976", "00d772b07788536b688ff2b84a", "fda8665f87c618646a89c7abdca275fd10c31453ad4b9c99", "93cc986c5b426cdf1e4538418c383c4e36378d7f9471799f3f6c6f7cc494201069344e2d6d41bd9b", "860f4428259d9c5b17698cc95363db6cfee603258582e3a3e8feb886599d4ac4"), TestFixture(16, "4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976", "00d772b07788536b688ff2b84a", "98104fd3f3413ad1f57ef4912cb50097dca379a58c47b0d2", "f674b1e02fc54e6a81b20b7b7c2f4924fa57e089b57d55d43787a15352cfceb028202c8730beaa7a", "1b43c482f83780c21583f88e5afcf6938edd20f21b74d895161b60c27a6a42f0"), TestFixture(16, "4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976", "00d772b07788536b688ff2b84a", "b46b343e64d2d70e0bd909dbb3f6bedf7e4adc74321be526", "da0fca0db856a3b57f15f631e36cf76c58be45580b210020f3a0ca3da647eb31893e867956097983", "b082ccd964617c27a5607b7324faad237ee53acfc18c35502dbf7c1937a9dfcb"), TestFixture(16, "4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976", "00d772b07788536b688ff2b84a", "8e12620bb575e6b167b085255b2b5631ff28e04cbef8826d", "e0769c3869f1920a137c7acf0bb11f82d9dc796087c2676be663fbbebbc251b9f1760afa49e89e71", "b8539ba93ef17254ec1d8d62e8f4eae4d41ee1e75345bf90c9cbb26c63bce501"), TestFixture(16, "4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976", "00d772b07788536b688ff2b84a", "792aaa23b923d1b53173fe19853b9aa402a301d48529873e", "174e541065a7a50e45bf01f3d5a1d317245798f8bc136238da90cd87e9d9ca5d85430a150e682752", "b6b09463b5ef5ead1f17f4021693a0d8452e98dcbb8e7590f9fde6394970a6f8"), TestFixture(16, "4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976", "00d772b07788536b688ff2b84a", "ddc5b4e48970ebd72869be6998e9103c014475e8ae6ea29c", "b3a14ad755f49f6c5ca54183c873598f27b0ecc49754479afc0cc4601afb61efa7059cfe49ec9dde", "390f6de14d5e1f2f78dbe757c00b89209d0cf8bc48cbbea035779f93de357905"), TestFixture(16, "4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976", "00d772b07788536b688ff2b84a", "d2b66096c475a77648c27235e6972ba8f18761330d3c6adf", "bcd29ea518f1d3cd3c0e8ddfb60d621bd773f81f34068fd9cf7474962c3602dcfcb50039f43e3d6f", "1d75c9e7acb09932db332498d30f82e4009025cb1827047c59a8f97812b568a4") ] func testEncrypt(fixture: TestFixture) -> Bool { let aes = try! AES(key: fixture.key, blockMode: CCM(iv: fixture.nonce, tagLength: fixture.tagLength, messageLength: fixture.plaintext.count, additionalAuthenticatedData: fixture.aad), padding: .noPadding) let encrypted = try! aes.encrypt(fixture.plaintext) if encrypted != fixture.expected { return false } return true } func testDecrypt(fixture: TestFixture) -> Bool { let aes = try! AES(key: fixture.key, blockMode: CCM(iv: fixture.nonce, tagLength: fixture.tagLength, messageLength: fixture.plaintext.count /*- fixture.tagLength*/, additionalAuthenticatedData: fixture.aad), padding: .noPadding) let plaintext = try! aes.decrypt(fixture.expected) if plaintext != fixture.plaintext { return false } return true } for (i, fixture) in fixtures.enumerated() { XCTAssertTrue(testEncrypt(fixture: fixture), "Encryption failed") XCTAssertTrue(testDecrypt(fixture: fixture), "(\(i) - Decryption failed.") } } func testAESCCMTestCase1() { let key: Array = [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f] let nonce: Array = [0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16] let aad: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07] let plaintext: Array = [0x20, 0x21, 0x22, 0x23] let expected: Array = [0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d] let aes = try! AES(key: key, blockMode: CCM(iv: nonce, tagLength: 4, messageLength: plaintext.count, additionalAuthenticatedData: aad), padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(encrypted, expected, "encryption failed") } func testAESCCMTestCase1Decrypt() { let key: Array = [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f] let nonce: Array = [0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16] let aad: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07] let ciphertext: Array = [0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d] let expected: Array = [0x20, 0x21, 0x22, 0x23] let aes = try! AES(key: key, blockMode: CCM(iv: nonce, tagLength: 4, messageLength: ciphertext.count - 4, additionalAuthenticatedData: aad), padding: .noPadding) let decrypted = try! aes.decrypt(ciphertext) XCTAssertEqual(decrypted, expected, "decryption failed") } func testAESCCMTestCase2() { let key: Array = [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f] let nonce: Array = [0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17] let aad: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let plaintext: Array = [0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f] let expected: Array = [0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd] let aes = try! AES(key: key, blockMode: CCM(iv: nonce, tagLength: 6, messageLength: plaintext.count, additionalAuthenticatedData: aad), padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(encrypted, expected, "encryption failed") } func testAESCCMTestCase2Decrypt() { let key: Array = [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f] let nonce: Array = [0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17] let aad: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let ciphertext: Array = [0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd] let expected: Array = [0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f] let aes = try! AES(key: key, blockMode: CCM(iv: nonce, tagLength: 6, messageLength: ciphertext.count - 6, additionalAuthenticatedData: aad), padding: .noPadding) let plaintext = try! aes.decrypt(ciphertext) XCTAssertEqual(plaintext, expected, "encryption failed") } func testAESCCMTestCase3() { let key: Array = [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f] let nonce: Array = [0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b] let aad: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13] let plaintext: Array = [0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37] let expected: Array = [0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51] let aes = try! AES(key: key, blockMode: CCM(iv: nonce, tagLength: 8, messageLength: plaintext.count, additionalAuthenticatedData: aad), padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(encrypted, expected, "encryption failed") } func testAESCCMTestCase3Decrypt() { let key: Array = [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f] let nonce: Array = [0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b] let aad: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13] let ciphertext: Array = [0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51] let expected: Array = [0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37] let aes = try! AES(key: key, blockMode: CCM(iv: nonce, tagLength: 8, messageLength: ciphertext.count - 8, additionalAuthenticatedData: aad), padding: .noPadding) let plaintext = try! aes.decrypt(ciphertext) XCTAssertEqual(plaintext, expected, "encryption failed") } func testAESCCMTestCase3DecryptPartial() { let key: Array = [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f] let nonce: Array = [0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b] let aad: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13] let ciphertext: Array = [0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51] let expected: Array = [0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37] let aes = try! AES(key: key, blockMode: CCM(iv: nonce, tagLength: 8, messageLength: ciphertext.count - 8, additionalAuthenticatedData: aad), padding: .noPadding) var decryptor = try! aes.makeDecryptor() var plaintext = [UInt8]() plaintext += try! decryptor.update(withBytes: Array(ciphertext[0..<2])) plaintext += try! decryptor.update(withBytes: Array(ciphertext[2..<6])) plaintext += try! decryptor.update(withBytes: Array(ciphertext[6..<32]), isLast: true) XCTAssertEqual(plaintext, expected, "encryption failed") } } ================================================ FILE: Tests/CryptoSwiftTests/AESOCBTests.swift ================================================ // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation import XCTest @testable import CryptoSwift final class OCBTests: XCTestCase { struct TestFixture { let N: Array let A: Array let P: Array let C: Array } func testAESOCBWithRFC7253Tests() { let K = Array(hex: "000102030405060708090A0B0C0D0E0F") let fixtures = [ TestFixture(N: Array(hex: "BBAA99887766554433221100"), A: Array(hex: ""), P: Array(hex: ""), C: Array(hex: "785407BFFFC8AD9EDCC5520AC9111EE6")), TestFixture(N: Array(hex: "BBAA99887766554433221101"), A: Array(hex: "0001020304050607"), P: Array(hex: "0001020304050607"), C: Array(hex: "6820B3657B6F615A5725BDA0D3B4EB3A257C9AF1F8F03009")), TestFixture(N: Array(hex: "BBAA99887766554433221102"), A: Array(hex: "0001020304050607"), P: Array(hex: ""), C: Array(hex: "81017F8203F081277152FADE694A0A00")), TestFixture(N: Array(hex: "BBAA99887766554433221103"), A: Array(hex: ""), P: Array(hex: "0001020304050607"), C: Array(hex: "45DD69F8F5AAE72414054CD1F35D82760B2CD00D2F99BFA9")), TestFixture(N: Array(hex: "BBAA99887766554433221104"), A: Array(hex: "000102030405060708090A0B0C0D0E0F"), P: Array(hex: "000102030405060708090A0B0C0D0E0F"), C: Array(hex: "571D535B60B277188BE5147170A9A22C3AD7A4FF3835B8C5701C1CCEC8FC3358")), TestFixture(N: Array(hex: "BBAA99887766554433221105"), A: Array(hex: "000102030405060708090A0B0C0D0E0F"), P: Array(hex: ""), C: Array(hex: "8CF761B6902EF764462AD86498CA6B97")), TestFixture(N: Array(hex: "BBAA99887766554433221106"), A: Array(hex: ""), P: Array(hex: "000102030405060708090A0B0C0D0E0F"), C: Array(hex: "5CE88EC2E0692706A915C00AEB8B2396F40E1C743F52436BDF06D8FA1ECA343D")), TestFixture(N: Array(hex: "BBAA99887766554433221107"), A: Array(hex: "000102030405060708090A0B0C0D0E0F1011121314151617"), P: Array(hex: "000102030405060708090A0B0C0D0E0F1011121314151617"), C: Array(hex: "1CA2207308C87C010756104D8840CE1952F09673A448A122C92C62241051F57356D7F3C90BB0E07F")), TestFixture(N: Array(hex: "BBAA99887766554433221108"), A: Array(hex: "000102030405060708090A0B0C0D0E0F1011121314151617"), P: Array(hex: ""), C: Array(hex: "6DC225A071FC1B9F7C69F93B0F1E10DE")), TestFixture(N: Array(hex: "BBAA99887766554433221109"), A: Array(hex: ""), P: Array(hex: "000102030405060708090A0B0C0D0E0F1011121314151617"), C: Array(hex: "221BD0DE7FA6FE993ECCD769460A0AF2D6CDED0C395B1C3CE725F32494B9F914D85C0B1EB38357FF")), TestFixture(N: Array(hex: "BBAA9988776655443322110A"), A: Array(hex: "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"), P: Array(hex: "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"), C: Array(hex: "BD6F6C496201C69296C11EFD138A467ABD3C707924B964DEAFFC40319AF5A48540FBBA186C5553C68AD9F592A79A4240")), TestFixture(N: Array(hex: "BBAA9988776655443322110B"), A: Array(hex: "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"), P: Array(hex: ""), C: Array(hex: "FE80690BEE8A485D11F32965BC9D2A32")), TestFixture(N: Array(hex: "BBAA9988776655443322110C"), A: Array(hex: ""), P: Array(hex: "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"), C: Array(hex: "2942BFC773BDA23CABC6ACFD9BFD5835BD300F0973792EF46040C53F1432BCDFB5E1DDE3BC18A5F840B52E653444D5DF")), TestFixture(N: Array(hex: "BBAA9988776655443322110D"), A: Array(hex: "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627"), P: Array(hex: "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627"), C: Array(hex: "D5CA91748410C1751FF8A2F618255B68A0A12E093FF454606E59F9C1D0DDC54B65E8628E568BAD7AED07BA06A4A69483A7035490C5769E60")), TestFixture(N: Array(hex: "BBAA9988776655443322110E"), A: Array(hex: "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627"), P: Array(hex: ""), C: Array(hex: "C5CD9D1850C141E358649994EE701B68")), TestFixture(N: Array(hex: "BBAA9988776655443322110F"), A: Array(hex: ""), P: Array(hex: "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627"), C: Array(hex: "4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15A5DDBFC5787E50B5CC55EE507BCB084E479AD363AC366B95A98CA5F3000B1479")), ] func testEncrypt(fixture: TestFixture) -> Bool { let ocb = OCB(nonce: fixture.N, additionalAuthenticatedData: fixture.A, mode: .combined) let aes = try! AES(key: K, blockMode: ocb, padding: .noPadding) let encrypted = try! aes.encrypt(fixture.P) if encrypted != fixture.C { return false } return true } func testDecrypt(fixture: TestFixture) -> Bool { let ocb = OCB(nonce: fixture.N, additionalAuthenticatedData: fixture.A, mode: .combined) let aes = try! AES(key: K, blockMode: ocb, padding: .noPadding) let plaintext = try! aes.decrypt(fixture.C) if plaintext != fixture.P { return false } return true } func testInvalidTag(fixture: TestFixture) -> Bool { let ocb = OCB(nonce: fixture.N, additionalAuthenticatedData: fixture.A, mode: .combined) let aes = try! AES(key: K, blockMode: ocb, padding: .noPadding) var C_ = fixture.C.slice C_[C_.count - 1] ^= 0x01 let plaintext = try? aes.decrypt(C_) return plaintext == nil } for (i, fixture) in fixtures.enumerated() { XCTAssertTrue(testEncrypt(fixture: fixture), "Encryption failed") XCTAssertTrue(testDecrypt(fixture: fixture), "(\(i) - Decryption failed.") XCTAssertTrue(testInvalidTag(fixture: fixture), "(\(i) - Invalid Tag verification failed.") } } static let allTests = [ ("testAESOCBWithRFC7253Tests", testAESOCBWithRFC7253Tests), ] } ================================================ FILE: Tests/CryptoSwiftTests/AESTests.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation import XCTest @testable import CryptoSwift final class AESTests: XCTestCase { // 128 bit key let aesKey: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] func testAESEncrypt() { let input: Array = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff] let expected: Array = [0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x4, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a] let aes = try! AES(key: self.aesKey, blockMode: ECB(), padding: .noPadding) let encrypted = try! aes.encrypt(input) XCTAssertEqual(encrypted, expected, "encryption failed") let decrypted = try! aes.decrypt(encrypted) XCTAssertEqual(decrypted, input, "decryption failed") } func testAESEncrypt2() { let key: Array = [0x36, 0x37, 0x39, 0x66, 0x62, 0x31, 0x64, 0x64, 0x66, 0x37, 0x64, 0x38, 0x31, 0x62, 0x65, 0x65] let iv: Array = [0x6b, 0x64, 0x66, 0x36, 0x37, 0x33, 0x39, 0x38, 0x44, 0x46, 0x37, 0x33, 0x38, 0x33, 0x66, 0x64] let input: Array = [0x62, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] let expected: Array = [0xae, 0x8c, 0x59, 0x95, 0xb2, 0x6f, 0x8e, 0x3d, 0xb0, 0x6f, 0x0a, 0xa5, 0xfe, 0xc4, 0xf0, 0xc2] let aes = try! AES(key: key, blockMode: CBC(iv: iv), padding: .noPadding) do { let encrypted = try aes.encrypt(input) XCTAssertEqual(encrypted, expected, "encryption failed") let decrypted = try aes.decrypt(encrypted) XCTAssertEqual(decrypted, input, "decryption failed") } catch { XCTFail("\(error)") } } func testAESEncrypt3() { let key = "679fb1ddf7d81bee" let iv = "kdf67398DF7383fd" let input: Array = [0x62, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] let expected: Array = [0xae, 0x8c, 0x59, 0x95, 0xb2, 0x6f, 0x8e, 0x3d, 0xb0, 0x6f, 0x0a, 0xa5, 0xfe, 0xc4, 0xf0, 0xc2] do { let aes = try AES(key: key, iv: iv, padding: .noPadding) let encrypted = try aes.encrypt(input) XCTAssertEqual(encrypted, expected, "encryption failed") let decrypted = try aes.decrypt(encrypted) XCTAssertEqual(decrypted, input, "decryption failed") } catch { XCTFail("\(error)") } } func testAESEncryptCBCNoPadding() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let plaintext: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a] let expected: Array = [0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d] let aes = try! AES(key: key, blockMode: CBC(iv: iv), padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(encrypted, expected, "encryption failed") let decrypted = try! aes.decrypt(encrypted) XCTAssertEqual(decrypted, plaintext, "decryption failed") } func testAESEncryptCBCWithPadding() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let plaintext: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a] let expected: Array = [0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, 0x89, 0x64, 0xe0, 0xb1, 0x49, 0xc1, 0x0b, 0x7b, 0x68, 0x2e, 0x6e, 0x39, 0xaa, 0xeb, 0x73, 0x1c] let aes = try! AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(encrypted, expected, "encryption failed") let decrypted = try! aes.decrypt(encrypted) XCTAssertEqual(decrypted, plaintext, "decryption failed") } func testAESEncryptCBCWithPaddingPartial() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let plaintext: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a] let aes = try! AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7) var ciphertext = Array() var encryptor = try! aes.makeEncryptor() ciphertext += try! encryptor.update(withBytes: plaintext[0..<8]) ciphertext += try! encryptor.update(withBytes: plaintext[8..<16]) ciphertext += try! encryptor.update(withBytes: plaintext[16..<32]) ciphertext += try! encryptor.finish() XCTAssertEqual(try! aes.encrypt(plaintext), ciphertext, "encryption failed") } func testAESEncryptIncremental() { do { var ciphertext = Array() let plaintext = "Today Apple launched the open source Swift community, as well as amazing new tools and resources." let aes = try AES(key: "passwordpassword".bytes, blockMode: CBC(iv: "drowssapdrowssap".bytes)) var encryptor = try! aes.makeEncryptor() ciphertext += try encryptor.update(withBytes: plaintext.bytes) ciphertext += try encryptor.finish() XCTAssertEqual(try aes.encrypt(plaintext.bytes), ciphertext, "encryption failed") } catch { XCTFail("\(error)") } } func testAESDecryptCBCWithPaddingPartial() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let ciphertext: Array = [118, 73, 171, 172, 129, 25, 178, 70, 206, 233, 142, 155, 18, 233, 25, 125, 76, 187, 200, 88, 117, 107, 53, 129, 37, 82, 158, 150, 152, 163, 143, 68, 169, 105, 137, 234, 93, 98, 239, 215, 41, 45, 51, 254, 138, 92, 251, 17] let aes = try! AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7) var plaintext = Array() var decryptor = try! aes.makeDecryptor() plaintext += try! decryptor.update(withBytes: ciphertext[0..<8]) plaintext += try! decryptor.update(withBytes: ciphertext[8..<16]) plaintext += try! decryptor.update(withBytes: ciphertext[16..<32]) plaintext += try! decryptor.finish() XCTAssertEqual(try! aes.decrypt(ciphertext), plaintext, "encryption failed") } func testAESEncryptCFB() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let plaintext: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a] let expected: Array = [0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a] let aes = try! AES(key: key, blockMode: CFB(iv: iv), padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(encrypted, expected, "encryption failed") let decrypted = try! aes.decrypt(encrypted) XCTAssertEqual(decrypted, plaintext, "decryption failed") } // https://github.com/krzyzanowskim/CryptoSwift/issues/142 func testAESEncryptCFBLong() { let key: Array = [56, 118, 37, 51, 125, 78, 103, 107, 119, 40, 74, 88, 117, 112, 123, 75, 122, 89, 72, 36, 46, 91, 106, 60, 54, 110, 34, 126, 69, 126, 61, 87] let iv: Array = [69, 122, 99, 87, 83, 112, 110, 65, 54, 109, 107, 89, 73, 122, 74, 49] let plaintext: Array = [123, 10, 32, 32, 34, 67, 111, 110, 102, 105, 114, 109, 34, 32, 58, 32, 34, 116, 101, 115, 116, 105, 110, 103, 34, 44, 10, 32, 32, 34, 70, 105, 114, 115, 116, 78, 97, 109, 101, 34, 32, 58, 32, 34, 84, 101, 115, 116, 34, 44, 10, 32, 32, 34, 69, 109, 97, 105, 108, 34, 32, 58, 32, 34, 116, 101, 115, 116, 64, 116, 101, 115, 116, 46, 99, 111, 109, 34, 44, 10, 32, 32, 34, 76, 97, 115, 116, 78, 97, 109, 101, 34, 32, 58, 32, 34, 84, 101, 115, 116, 101, 114, 34, 44, 10, 32, 32, 34, 80, 97, 115, 115, 119, 111, 114, 100, 34, 32, 58, 32, 34, 116, 101, 115, 116, 105, 110, 103, 34, 44, 10, 32, 32, 34, 85, 115, 101, 114, 110, 97, 109, 101, 34, 32, 58, 32, 34, 84, 101, 115, 116, 34, 10, 125] let encrypted: Array = try! AES(key: key, blockMode: CFB(iv: iv)).encrypt(plaintext) let decrypted: Array = try! AES(key: key, blockMode: CFB(iv: iv)).decrypt(encrypted) XCTAssert(decrypted == plaintext, "decryption failed") } // https://github.com/krzyzanowskim/CryptoSwift/issues/500 func testAESEncryptCFB8() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let plaintext: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d] let expected: Array = [0x3b, 0x79, 0x42, 0x4c, 0x9c, 0x0d, 0xd4, 0x36, 0xba, 0xce, 0x9e, 0x0e, 0xd4, 0x58, 0x6a, 0x4f, 0x32, 0xb9] let aes = try! AES(key: key, blockMode: CFB(iv: iv, segmentSize: .cfb8), padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(encrypted, expected, "encryption failed") let decrypted = try! aes.decrypt(encrypted) XCTAssertEqual(decrypted, plaintext, "decryption failed") } func testAESEncryptOFB128() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let plaintext: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a] let expected: Array = [0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a] let aes = try! AES(key: key, blockMode: OFB(iv: iv), padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(encrypted, expected, "encryption failed") let decrypted = try! aes.decrypt(encrypted) XCTAssertEqual(decrypted, plaintext, "decryption failed") } func testAESEncryptOFB256() { let key: Array = [0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let plaintext: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a] let expected: Array = [0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60] let aes = try! AES(key: key, blockMode: OFB(iv: iv), padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(encrypted, expected, "encryption failed") let decrypted = try! aes.decrypt(encrypted) XCTAssertEqual(decrypted, plaintext, "decryption failed") } func testAESEncryptPCBC256() { let key: Array = [0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let plaintext: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a] let expected: Array = [0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6] let aes = try! AES(key: key, blockMode: PCBC(iv: iv), padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) print(encrypted.toHexString()) XCTAssertEqual(encrypted, expected, "encryption failed") let decrypted = try! aes.decrypt(encrypted) XCTAssertEqual(decrypted, plaintext, "decryption failed") } func testAESEncryptBigPCBC128() { let key = "0123456789abcdef".bytes let iv = "fedcba9876543210".bytes let plaintext = "64 byte plaintext that will split into 4 chunks of 16 bytes each".bytes let ciphertext: Array = [0xd6, 0x83, 0x7b, 0xb8, 0xfe, 0x1d, 0x62, 0xf7, 0x04, 0x69, 0xd1, 0xfd, 0x47, 0x06, 0x9c, 0x3d, 0xc0, 0x7c, 0xfe, 0xc9, 0x3d, 0xba, 0x35, 0x61, 0x40, 0xef, 0xe2, 0xac, 0xc6, 0x4c, 0x3d, 0x04, 0xbf, 0x4c, 0xa4, 0xf6, 0xfc, 0x09, 0xfc, 0x8c, 0x2e, 0x09, 0xd0, 0x74, 0x66, 0x2b, 0x8f, 0x02, 0x54, 0x01, 0x25, 0x76, 0x20, 0x88, 0x5e, 0x19, 0x3f, 0x74, 0xcd, 0x48, 0x29, 0xc7, 0xe1, 0xc6, 0xfb, 0xc9, 0xb9, 0xcf, 0xcd, 0xf8, 0xeb, 0x42, 0xbc, 0x0f, 0xc5, 0x73, 0x96, 0xe4, 0xf8, 0x0f] let aes = try! AES(key: key, blockMode: PCBC(iv: iv), padding: .pkcs7) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(encrypted, ciphertext, "encryption failed") let decrypted = try! aes.decrypt(ciphertext) XCTAssertEqual(decrypted, plaintext, "decryption failed") } func testAESEncryptCTR() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let iv: Array = [0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff] let plaintext: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a] let expected: Array = [0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce] let aes = try! AES(key: key, blockMode: CTR(iv: iv), padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(encrypted.count, plaintext.count) XCTAssertEqual(encrypted, expected, "encryption failed") let decrypted = try! aes.decrypt(encrypted) XCTAssertEqual(decrypted.count, plaintext.count) XCTAssertEqual(decrypted, plaintext, "decryption failed") } // https://github.com/krzyzanowskim/CryptoSwift/issues/424 func testAESEncryptCTRZeroPadding() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let iv: Array = [0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff] let plaintext: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0x01] let expected: Array = [0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce, 0x37, 0x2b, 0x7c, 0x3c, 0x67, 0x73, 0x51, 0x63, 0x18, 0xa0, 0x77, 0xd7, 0xfc, 0x50, 0x73, 0xae] let aes = try! AES(key: key, blockMode: CTR(iv: iv), padding: .zeroPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(plaintext.count, 17) XCTAssertEqual(encrypted.count, 32, "padding failed") XCTAssertEqual(encrypted, expected, "encryption failed") } func testAESEncryptCTRIrregularLength() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let iv: Array = [0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff] let plaintext: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0x01] let expected: Array = [0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce, 0x37] let aes = try! AES(key: key, blockMode: CTR(iv: iv), padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(encrypted, expected, "encryption failed") let decrypted = try! aes.decrypt(encrypted) XCTAssertEqual(decrypted, plaintext, "decryption failed") } // https://github.com/krzyzanowskim/CryptoSwift/pull/290 func testAESDecryptCTRSeek() { let key: Array = [0x52, 0x72, 0xb5, 0x9c, 0xab, 0x07, 0xc5, 0x01, 0x11, 0x7a, 0x39, 0xb6, 0x10, 0x35, 0x87, 0x02] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01] var plaintext: Array = Array(repeating: 0, count: 6000) for i in 0.. = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let iv: Array = [0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff] let plaintext: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0x01, 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0x01] let expected: Array = [0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0xd, 0xb6, 0xce, 0x37, 0x40, 0xbd, 0x82, 0x85, 0x5d, 0x11, 0xfc, 0x8e, 0x49, 0x4a, 0xa9, 0xed, 0x23, 0xe0, 0xb9, 0x40, 0x2d] let aes = try! AES(key: key, blockMode: CTR(iv: iv), padding: .noPadding) var encryptor = try! aes.makeEncryptor() var encrypted = Array() encrypted += try! encryptor.update(withBytes: plaintext[0..<5]) encrypted += try! encryptor.update(withBytes: plaintext[5..<15]) encrypted += try! encryptor.update(withBytes: plaintext[15...]) encrypted += try! encryptor.finish() XCTAssertEqual(encrypted, expected, "encryption failed") var decryptor = try! aes.makeDecryptor() var decrypted = Array() decrypted += try! decryptor.update(withBytes: expected[0..<5]) decrypted += try! decryptor.update(withBytes: expected[5..<15]) decrypted += try! decryptor.update(withBytes: expected[15...]) decrypted += try! decryptor.finish() XCTAssertEqual(decrypted, plaintext, "decryption failed") } func testAESEncryptCTRStream() { let key = Array(hex: "0xbe3e9020816eb838782e2d9f4a2f40d4") let iv = Array(hex: "0x0000000000000000a9bbd681ded0c0c8") do { let aes = try AES(key: key, blockMode: CTR(iv: iv), padding: .noPadding) var encryptor = try aes.makeEncryptor() let encrypted1 = try encryptor.update(withBytes: [0x00, 0x01, 0x02, 0x03] as [UInt8]) XCTAssertEqual(encrypted1, Array(hex: "d79d0344")) let encrypted2 = try encryptor.update(withBytes: [0x04, 0x05, 0x06, 0x07] as [UInt8]) XCTAssertEqual(encrypted2, Array(hex: "b2a08879")) let encrypted3 = try encryptor.update(withBytes: [0x08] as [UInt8]) XCTAssertEqual(encrypted3, Array(hex: "db")) } catch { XCTFail(error.localizedDescription) } } func testAESWithWrongKey() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let key2: Array = [0x22, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x33] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let plaintext: Array = [49, 46, 50, 50, 50, 51, 51, 51, 51] let aes = try! AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7) let aes2 = try! AES(key: key2, blockMode: CBC(iv: iv), padding: .pkcs7) let encrypted = try! aes.encrypt(plaintext) let decrypted = try? aes2.decrypt(encrypted) XCTAssertTrue(decrypted! != plaintext, "failed") } // https://github.com/krzyzanowskim/CryptoSwift/issues/298 func testIssue298() { let encryptedValue = "47595cfa90f7b0b0e0d9d7240a2e035f7f4acde27d7ca778a7d8b05add32a0a92d945c0a59f7f0e029d7f2fbb258b2f0" let expected: Array = [55, 52, 98, 54, 53, 51, 101, 51, 54, 52, 51, 48, 100, 55, 97, 57, 99, 100, 57, 49, 97, 50, 52, 100, 57, 57, 52, 52, 98, 48, 51, 50, 79, 114, 70, 101, 99, 107, 114, 87, 111, 0, 0, 0, 0, 0, 0, 0] let key = "0123456789abcdef" let iv = "fedcba9876543210" do { let aes = try AES(key: key, iv: iv, padding: .noPadding) let ciphertext = try aes.decrypt(Array(hex: encryptedValue)) XCTAssertEqual(ciphertext, expected) } catch { XCTFail("failed") } } // https://github.com/krzyzanowskim/CryptoSwift/issues/394 func testIssue394() { let plaintext = "Nullam quis risus eget urna mollis ornare vel eu leo.".bytes let key = "passwordpassword".bytes.md5() // -md md5 let iv = "drowssapdrowssap".bytes // -iv 64726f777373617064726f7773736170 let aes = try! AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7) // -aes-128-cbc let ciphertext = try! aes.encrypt(plaintext) // enc // $ echo -n "Nullam quis risus eget urna mollis ornare vel eu leo." | openssl enc -aes-128-cbc -md md5 -nosalt -iv 64726f777373617064726f7773736170 -pass pass:passwordpassword -base64 // cij+965z2Xqoj9tIHgtA72ZPfv5sxnt76vwkIt1CodYY313oa7mr0pSc5o++g0CX // YczxK2fGIa84xtwDtRMwBQ== XCTAssertEqual(ciphertext.toBase64(), "cij+965z2Xqoj9tIHgtA72ZPfv5sxnt76vwkIt1CodYY313oa7mr0pSc5o++g0CXYczxK2fGIa84xtwDtRMwBQ==") } // https://github.com/krzyzanowskim/CryptoSwift/issues/411 func testIssue411() { let ciphertext: Array = [0x2a, 0x3a, 0x80, 0x05, 0xaf, 0x46, 0x58, 0x2d, 0x66, 0x52, 0x10, 0xae, 0x86, 0xd3, 0x8e, 0x8f] // test let key = "passwordpassword".bytes.md5() // -md md5 let iv = "drowssapdrowssap".bytes // -iv 64726f777373617064726f7773736170 let aes = try! AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7) // -aes-128-cbc let plaintext = try! ciphertext.decrypt(cipher: aes) XCTAssertEqual("74657374", plaintext.toHexString()) } } // MARK: - GCM extension AESTests { func testAESGCMTestCase1() { // Test Case 1 let key = Array(hex: "0x00000000000000000000000000000000") let iv = Array(hex: "0x000000000000000000000000") let gcm = GCM(iv: iv, mode: .detached) let aes = try! AES(key: key, blockMode: gcm, padding: .noPadding) let encrypted = try! aes.encrypt([UInt8]()) XCTAssertEqual(Array(encrypted), [UInt8](hex: "")) // C XCTAssertEqual(gcm.authenticationTag, [UInt8](hex: "58e2fccefa7e3061367f1d57a4e7455a")) // T (128-bit) } func testAESGCMTestCase2() { // Test Case 2 let key = Array(hex: "0x00000000000000000000000000000000") let plaintext = Array(hex: "0x00000000000000000000000000000000") let iv = Array(hex: "0x000000000000000000000000") let gcm = GCM(iv: iv, mode: .detached) let aes = try! AES(key: key, blockMode: gcm, padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(Array(encrypted), [UInt8](hex: "0388dace60b6a392f328c2b971b2fe78")) // C XCTAssertEqual(gcm.authenticationTag, [UInt8](hex: "ab6e47d42cec13bdf53a67b21257bddf")) // T (128-bit) } func testAESGCMTestCase3() { // Test Case 3 let key = Array(hex: "0xfeffe9928665731c6d6a8f9467308308") let plaintext = Array(hex: "0xd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255") let iv = Array(hex: "0xcafebabefacedbaddecaf888") let encGCM = GCM(iv: iv, mode: .detached) let aes = try! AES(key: key, blockMode: encGCM, padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertNotNil(encGCM.authenticationTag) XCTAssertEqual(Array(encrypted), [UInt8](hex: "0x42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985")) // C XCTAssertEqual(encGCM.authenticationTag, [UInt8](hex: "0x4d5c2af327cd64a62cf35abd2ba6fab4")) // T (128-bit) // decrypt func decrypt(_ encrypted: Array, tag: Array) -> Array { let decGCM = GCM(iv: iv, authenticationTag: tag, mode: .detached) let aes = try! AES(key: key, blockMode: decGCM, padding: .noPadding) return try! aes.decrypt(encrypted) } let decrypted = decrypt(encrypted, tag: encGCM.authenticationTag!) XCTAssertEqual(decrypted, plaintext) } func testAESGCMTestCase3Combined() { // Test Case 3 let key = Array(hex: "0xfeffe9928665731c6d6a8f9467308308") let plaintext = Array(hex: "0xd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255") let iv = Array(hex: "0xcafebabefacedbaddecaf888") let encGCM = GCM(iv: iv, mode: .combined) let aes = try! AES(key: key, blockMode: encGCM, padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertNotNil(encGCM.authenticationTag) XCTAssertEqual(Array(encrypted), [UInt8](hex: "0x42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4")) // C XCTAssertEqual(encGCM.authenticationTag, [UInt8](hex: "0x4d5c2af327cd64a62cf35abd2ba6fab4")) // T (128-bit) // decrypt func decrypt(_ encrypted: Array) -> Array { let decGCM = GCM(iv: iv, mode: .combined) let aes = try! AES(key: key, blockMode: decGCM, padding: .noPadding) return try! aes.decrypt(encrypted) } let decrypted = decrypt(encrypted) XCTAssertEqual(decrypted, plaintext) } func testAESGCMTestCase4() { // Test Case 4 let key = Array(hex: "0xfeffe9928665731c6d6a8f9467308308") let plaintext = Array(hex: "0xd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39") let iv = Array(hex: "0xcafebabefacedbaddecaf888") let auth = Array(hex: "0xfeedfacedeadbeeffeedfacedeadbeefabaddad2") let gcm = GCM(iv: iv, additionalAuthenticatedData: auth, mode: .detached) let aes = try! AES(key: key, blockMode: gcm, padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(Array(encrypted), [UInt8](hex: "0x42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091")) // C XCTAssertEqual(gcm.authenticationTag, [UInt8](hex: "0x5bc94fbc3221a5db94fae95ae7121a47")) // T (128-bit) } func testAESGCMTestCase5() { // Test Case 5 let key = Array(hex: "0xfeffe9928665731c6d6a8f9467308308") let plaintext = Array(hex: "0xd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39") let iv = Array(hex: "0xcafebabefacedbad") let auth = Array(hex: "0xfeedfacedeadbeeffeedfacedeadbeefabaddad2") let gcm = GCM(iv: iv, additionalAuthenticatedData: auth, mode: .detached) let aes = try! AES(key: key, blockMode: gcm, padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(Array(encrypted), [UInt8](hex: "0x61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598")) // C XCTAssertEqual(gcm.authenticationTag, [UInt8](hex: "0x3612d2e79e3b0785561be14aaca2fccb")) // T (128-bit) } func testAESGCMTestCase6() { // Test Case 6 let key = Array(hex: "0xfeffe9928665731c6d6a8f9467308308") let plaintext = Array(hex: "0xd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39") let iv = Array(hex: "0x9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b") let auth = Array(hex: "0xfeedfacedeadbeeffeedfacedeadbeefabaddad2") let gcm = GCM(iv: iv, additionalAuthenticatedData: auth, mode: .detached) let aes = try! AES(key: key, blockMode: gcm, padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(Array(encrypted), [UInt8](hex: "0x8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5")) // C XCTAssertEqual(gcm.authenticationTag, [UInt8](hex: "0x619cc5aefffe0bfa462af43c1699d050")) // T (128-bit) } func testAESGCMTestCase7() { // Test Case 7 let key = Array(hex: "0x000000000000000000000000000000000000000000000000") let plaintext = Array(hex: "") let iv = Array(hex: "0x000000000000000000000000") let gcm = GCM(iv: iv, mode: .detached) let aes = try! AES(key: key, blockMode: gcm, padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(Array(encrypted), [UInt8](hex: "")) // C XCTAssertEqual(gcm.authenticationTag, [UInt8](hex: "0xcd33b28ac773f74ba00ed1f312572435")) // T (128-bit) } func testAESGCMTagLengthDetached() { // Test Case 2 let key = Array(hex: "0x00000000000000000000000000000000") let plaintext = Array(hex: "0x00000000000000000000000000000000") let iv = Array(hex: "0x000000000000000000000000") let gcm = GCM(iv: iv, tagLength: 12, mode: .detached) let aes = try! AES(key: key, blockMode: gcm, padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(Array(encrypted), [UInt8](hex: "0388dace60b6a392f328c2b971b2fe78")) // C XCTAssertEqual(gcm.authenticationTag, [UInt8](hex: "ab6e47d42cec13bdf53a67b2")) // T (96-bit) // decrypt func decrypt(_ encrypted: Array) -> Array { let decGCM = GCM(iv: iv, authenticationTag: gcm.authenticationTag!, mode: .detached) let aes = try! AES(key: key, blockMode: decGCM, padding: .noPadding) return try! aes.decrypt(encrypted) } let decrypted = decrypt(encrypted) XCTAssertEqual(decrypted, plaintext) } func testAESGCMTagLengthCombined() { // Test Case 2 let key = Array(hex: "0x00000000000000000000000000000000") let plaintext = Array(hex: "0x00000000000000000000000000000000") let iv = Array(hex: "0x000000000000000000000000") let gcm = GCM(iv: iv, tagLength: 12, mode: .combined) let aes = try! AES(key: key, blockMode: gcm, padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertEqual(Array(encrypted), [UInt8](hex: "0388dace60b6a392f328c2b971b2fe78ab6e47d42cec13bdf53a67b2")) // C XCTAssertEqual(gcm.authenticationTag, [UInt8](hex: "ab6e47d42cec13bdf53a67b2")) // T (96-bit) // decrypt func decrypt(_ encrypted: Array) -> Array { let decGCM = GCM(iv: iv, authenticationTag: gcm.authenticationTag!, mode: .combined) let aes = try! AES(key: key, blockMode: decGCM, padding: .noPadding) return try! aes.decrypt(encrypted) } let decrypted = decrypt(encrypted) XCTAssertEqual(decrypted, plaintext) } func testAESGCMTagLengthCombined2() { let key = Array(hex: "0x00000000000000000000000000000000") let plaintext = Array(hex: "0x0000000000000000000000000000000000000000") let iv = Array(hex: "0x000000000000") let gcm = GCM(iv: iv, tagLength: 12, mode: .combined) let aes = try! AES(key: key, blockMode: gcm, padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) // decrypt func decrypt(_ encrypted: Array) -> Array { let decGCM = GCM(iv: iv, authenticationTag: gcm.authenticationTag!, mode: .combined) let aes = try! AES(key: key, blockMode: decGCM, padding: .noPadding) return try! aes.decrypt(encrypted) } let decrypted = decrypt(encrypted) XCTAssertEqual(decrypted, plaintext) } func testAESGCMTestCaseIrregularCombined1() { // echo -n "0123456789010123456789012345" | openssl enc -aes-128-gcm -K feffe9928665731c6d6a8f9467308308 -iv cafebabefacedbaddecaf888 -nopad -nosalt // openssl note: The enc program does not support authenticated encryption modes like CCM and GCM. The utility does not store or retrieve the authentication tag let key = Array(hex: "0xfeffe9928665731c6d6a8f9467308308") let plaintext = "0123456789010123456789012345".bytes let iv = Array(hex: "0xcafebabefacedbaddecaf888") let encGCM = GCM(iv: iv, mode: .combined) let aes = try! AES(key: key, blockMode: encGCM, padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertNotNil(encGCM.authenticationTag) XCTAssertEqual(Array(encrypted), [UInt8](hex: "0xab831ed4edc644f6d61218431b14c0355138be4b010f630b29be7a2b9793b9fbecc7b44cc86dfd697a50c1c6")) // C XCTAssertEqual(encGCM.authenticationTag, [UInt8](hex: "0x9793b9fbecc7b44cc86dfd697a50c1c6")) // T (128-bit) // decrypt func decrypt(_ encrypted: Array) -> Array { let decGCM = GCM(iv: iv, mode: .combined) let aes = try! AES(key: key, blockMode: decGCM, padding: .noPadding) return try! aes.decrypt(encrypted) } let decrypted = decrypt(encrypted) XCTAssertEqual(decrypted, plaintext) } func testAESGCMTestCaseIrregularCombined2() { // echo -n "0123456789010123456789012345012345678901012345678901234567" | openssl enc -aes-128-gcm -K feffe9928665731c6d6a8f9467308308 -iv cafebabefacedbaddecaf888 -nopad -nosalt // openssl note: The enc program does not support authenticated encryption modes like CCM and GCM. The utility does not store or retrieve the authentication tag let key = Array(hex: "0xfeffe9928665731c6d6a8f9467308308") let plaintext = "0123456789010123456789012345012345678901012345678901234567".bytes let iv = Array(hex: "0xcafebabefacedbaddecaf888") let encGCM = GCM(iv: iv, mode: .combined) let aes = try! AES(key: key, blockMode: encGCM, padding: .noPadding) let encrypted = try! aes.encrypt(plaintext) XCTAssertNotNil(encGCM.authenticationTag) XCTAssertEqual(Array(encrypted), [UInt8](hex: "0xab831ed4edc644f6d61218431b14c0355138be4b010f630b29be7a2b93ac196f09dc2e10f937aa7e6271564dd117291792f0d6fdf2347ef5b10c86a7f414f0c91a8e59fd2405b850527e")) // C XCTAssertEqual(encGCM.authenticationTag, [UInt8](hex: "0x86a7f414f0c91a8e59fd2405b850527e")) // T (128-bit) // decrypt func decrypt(_ encrypted: Array) -> Array { let decGCM = GCM(iv: iv, mode: .combined) let aes = try! AES(key: key, blockMode: decGCM, padding: .noPadding) return try! aes.decrypt(encrypted) } let decrypted = decrypt(encrypted) XCTAssertEqual(decrypted, plaintext) } } extension AESTests { static func allTests() -> [(String, (AESTests) -> () -> Void)] { let tests = [ ("testAESEncrypt", testAESEncrypt), ("testAESEncrypt2", testAESEncrypt2), ("testAESEncrypt3", testAESEncrypt3), ("testAESEncryptCBCNoPadding", testAESEncryptCBCNoPadding), ("testAESEncryptCBCWithPadding", testAESEncryptCBCWithPadding), ("testAESEncryptCBCWithPaddingPartial", testAESEncryptCBCWithPaddingPartial), ("testAESEncryptIncremental", testAESEncryptIncremental), ("testAESDecryptCBCWithPaddingPartial", testAESDecryptCBCWithPaddingPartial), ("testAESEncryptCFB", testAESEncryptCFB), ("testAESEncryptCFBLong", testAESEncryptCFBLong), ("testAESEncryptCFB8", testAESEncryptCFB8), ("testAESEncryptOFB128", testAESEncryptOFB128), ("testAESEncryptOFB256", testAESEncryptOFB256), ("testAESEncryptPCBC256", testAESEncryptPCBC256), ("testAESEncryptCTR", testAESEncryptCTR), ("testAESEncryptCTRZeroPadding", testAESEncryptCTRZeroPadding), ("testAESEncryptCTRIrregularLength", testAESEncryptCTRIrregularLength), ("testAESDecryptCTRSeek", testAESDecryptCTRSeek), ("testAESEncryptCTRIrregularLengthIncrementalUpdate", testAESEncryptCTRIrregularLengthIncrementalUpdate), ("testAESEncryptCTRStream", testAESEncryptCTRStream), ("testIssue298", testIssue298), ("testIssue394", testIssue394), ("testIssue411", testIssue411), ("testAESWithWrongKey", testAESWithWrongKey), ("testAESGCMTestCase1", testAESGCMTestCase1), ("testAESGCMTestCase2", testAESGCMTestCase2), ("testAESGCMTestCase3", testAESGCMTestCase3), ("testAESGCMTestCase3Combined", testAESGCMTestCase3Combined), ("testAESGCMTestCase4", testAESGCMTestCase4), ("testAESGCMTestCase5", testAESGCMTestCase5), ("testAESGCMTestCase6", testAESGCMTestCase6), ("testAESGCMTestCase7", testAESGCMTestCase7), ("testAESGCMTestTagLengthDetached", testAESGCMTagLengthDetached), ("testAESGCMTestTagLengthCombined", testAESGCMTagLengthCombined), ("testAESGCMTestCaseIrregularCombined1", testAESGCMTestCaseIrregularCombined1), ("testAESGCMTestCaseIrregularCombined2", testAESGCMTestCaseIrregularCombined2) ] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/AESTestsPerf.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation import XCTest @testable import CryptoSwift final class AESTestsPerf: XCTestCase { func testAESEncryptPerformance() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let message = Array(repeating: 7, count: 1024 * 1024) let aes = try! AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7) measure { _ = try! aes.encrypt(message) } } func testAESDecryptPerformance() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f] let message = Array(repeating: 7, count: 1024 * 1024) let aes = try! AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7) measure { _ = try! aes.decrypt(message) } } } extension AESTestsPerf { static func allTests() -> [(String, (AESTestsPerf) -> () -> Void)] { let tests = [ ("testAESEncryptPerformance", testAESEncryptPerformance), ("testAESDecryptPerformance", testAESDecryptPerformance) ] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/ASN1Tests.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2021 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import XCTest @testable import CryptoSwift final class ASN1Tests: XCTestCase { /// This test ensures that we get the same data out as we put in before and after encoding /// /// This test enforces that /// 1) The data provided to each of the `ASN1.Node`s is preserved across encoding and decoding. func testASN1NonDestructiveEncoding() throws { let arbitraryData = Data(hex: "0123456789") // Encode the serialized BigInteger let node: ASN1.Node = .sequence(nodes: [ .integer(data: arbitraryData), .bitString(data: arbitraryData), .octetString(data: arbitraryData), .null, .objectIdentifier(data: arbitraryData) ]) let encoded = ASN1.Encoder.encode(node) // Decode the Encoding let decoded = try ASN1.Decoder.decode(data: Data(encoded)) guard case .sequence(let sequence) = decoded else { XCTFail("Failed to recover encoded SEQUENCE") return } XCTAssertEqual(sequence.count, 5) guard case .integer(let integerData) = sequence[0] else { XCTFail("Failed to recover encoded INTEGER") return } XCTAssertEqual(integerData, arbitraryData) guard case .bitString(let bitStringData) = sequence[1] else { XCTFail("Failed to recover encoded BITSTRING") return } XCTAssertEqual(bitStringData, arbitraryData) guard case .octetString(let octetData) = sequence[2] else { XCTFail("Failed to recover encoded OCTETSTRING") return } XCTAssertEqual(octetData, arbitraryData) guard case .null = sequence[3] else { XCTFail("Failed to recover encoded NULL") return } guard case .objectIdentifier(let objIDData) = sequence[4] else { XCTFail("Failed to recover encoded OBJECTIDENTIFIER") return } XCTAssertEqual(objIDData, arbitraryData) } /// The ASN1 Encoder / Decoder doesn't handle encoding / decoding Integers directly, it's your responsibility to accurately serialize your integers. /// - Note: In this example we're using BigInteger's serialization technique to encode / decode Integers, which isn't the default method for handling integers. https://www.strozhevsky.com/free_docs/asn1_by_simple_words.pdf /// /// This test enforces that /// 1) The data provided to the `ASN1.Node.integer` Node is preserved across encoding and decoding. func testASN1DecodePrimitiveInteger() throws { let tests = [ 0, -0, 128, -128, 136, -136, 8388607, -8388607, 3409934108352718734, -3409934108352718734 ] for test in tests { let number = BigInteger(test) // Encode the serialized Integer let encoded = ASN1.Encoder.encode(.integer(data: number.serialize())) // Ensure the Integer Prefix was added XCTAssertEqual(Array(arrayLiteral: 0x02), Array(encoded.prefix(1))) // Decode the Encoding let decoded = try ASN1.Decoder.decode(data: Data(encoded)) guard case .integer(let num) = decoded else { XCTFail("Failed to recover encoded integer") return } // Ensure the original BigInteger was recovered XCTAssertEqual(BigInteger(num), number) } } /// Another test showing that Integers are stored as arbitrary data and the proper serialization and signage are the responsibilities of the user and their application. /// /// This test enforces that /// 1) The data provided to the `ASN1.Node.integer` Node is preserved across encoding and decoding. func testASN1DecodeLargeBigInteger() throws { // Because INTEGERS are stored as arbitrary data we should be able to store an integer that would otherwise overflow by using the BigInteger library let largeBigInt = BigInteger("1541235134652345698374107823450134507610354876134950342785028743653") // Encode the serialized BigInteger let encoded = ASN1.Encoder.encode(.integer(data: largeBigInt.serialize())) // Decode the Encoding let decoded = try ASN1.Decoder.decode(data: Data(encoded)) guard case .integer(let num) = decoded else { XCTFail("Failed to recover encoded integer") return } // Ensure the original BigInteger was recovered XCTAssertEqual(BigInteger(num), largeBigInt) } /// This tests decodes an RSA Public Key from a Base64 DER Encoded representation /// /// This test enforces that /// 1) The decoding process yields the expected format. /// 2) The re-encoding of the data yields the exact same starting data. func testANS1DERDecodingPublicKey() throws { /// An example of an RSA Public Key ASN1 DER Encoding /// /// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.1) /// ``` /// ========================= /// RSA PublicKey Structure /// ========================= /// /// RSAPublicKey ::= SEQUENCE { /// modulus INTEGER, -- n /// publicExponent INTEGER, -- e /// } /// ``` let publicDER = """ MIGJAoGBAMGeZvIG84vyKAATwKkKz2g+PeNaZ63rxk/zEnLGxkMCVKnUZ6jPAtzYOKM24949yIhfxYBC/bOCPwRK4wbr4YyIx3WB2v+Zcqe8pRM/BThUpNIx3K2+jbJBhAopf1GXJ3i31RuiLMh9HWhxzkVamz1KnDjCuTZguCRRHIv+r3XTAgMBAAE= """ guard let publicDERData = Data(base64Encoded: publicDER) else { XCTFail("Failed to convert base64 string into data for decoding.") return } let decoded = try ASN1.Decoder.decode(data: publicDERData) // Ensure the first node is of type Sequence guard case .sequence(let nodes) = decoded else { XCTFail("Expected the top level node to be a sequence and it wasn't") return } // Ensure there are two nodes within the top level sequence (our integers, n and e) XCTAssertEqual(nodes.count, 2) // Ensure that the first node within our sequence is of type Integer guard case .integer(let n) = nodes[0] else { XCTFail("Expected an integer within our sequence and it wasn't") return } // Ensure the second node within our sequence is of type Integer guard case .integer(let e) = nodes[1] else { XCTFail("Expected an integer within our sequence and it wasn't") return } // Ensure that n contains the data we expected XCTAssertEqual(n.toHexString(), "00c19e66f206f38bf2280013c0a90acf683e3de35a67adebc64ff31272c6c6430254a9d467a8cf02dcd838a336e3de3dc8885fc58042fdb3823f044ae306ebe18c88c77581daff9972a7bca5133f053854a4d231dcadbe8db241840a297f51972778b7d51ba22cc87d1d6871ce455a9b3d4a9c38c2b93660b824511c8bfeaf75d3") // Ensure that e contains the data we expected XCTAssertEqual(e.toHexString(), "010001") // 65537 // Re Encode the data let asn1: ASN1.Node = .sequence(nodes: [ .integer(data: n), .integer(data: e) ]) let encoded = ASN1.Encoder.encode(asn1) // Ensure the re-encoded data matches the original exactly XCTAssertEqual(Data(encoded), publicDERData) XCTAssertEqual(encoded, publicDERData.byteArray) XCTAssertEqual(encoded.toBase64(), publicDER) } /// This tests decodes an RSA Private Key from a Base64 DER Encoded representation /// /// This test enforces that /// 1) The decoding process yields the expected format. /// 2) The re-encoding of the data yields the exact same starting data. func testANS1DERDecodingPrivateKey() throws { /// An example of an RSA Private Key ASN1 DER Encoding /// /// [IETF Spec RFC2313](https://datatracker.ietf.org/doc/html/rfc2313#section-7.2) /// ``` /// ========================== /// RSA PrivateKey Structure /// ========================== /// /// RSAPrivateKey ::= SEQUENCE { /// version Version, /// modulus INTEGER, -- n /// publicExponent INTEGER, -- e /// privateExponent INTEGER, -- d /// prime1 INTEGER, -- p /// prime2 INTEGER, -- q /// exponent1 INTEGER, -- d mod (p-1) /// exponent2 INTEGER, -- d mod (q-1) /// coefficient INTEGER, -- (inverse of q) mod p /// otherPrimeInfos OtherPrimeInfos OPTIONAL /// } /// ``` let privateDER = """ MIICXQIBAAKBgQDBnmbyBvOL8igAE8CpCs9oPj3jWmet68ZP8xJyxsZDAlSp1GeozwLc2DijNuPePciIX8WAQv2zgj8ESuMG6+GMiMd1gdr/mXKnvKUTPwU4VKTSMdytvo2yQYQKKX9Rlyd4t9UboizIfR1occ5FWps9Spw4wrk2YLgkURyL/q910wIDAQABAoGAGJkNLxZe/pqHJmtcAJ3U98NgjW/A2EGp8iJJZ7eFHKJBK0pG2RVjobb+iw3AKU3kGh9AsijQnmufoeX5rblt7/ojgpfVhS7NHsKCi8Nx7U92bNnP0RP4mogpvzGWVknUdv6jW7dX83FKgEywbNKa5CPQk1XinqXL33gNjWdOh/ECQQDjdE4kNdVwKA59ddWRShvJiOMOG8+TjE5HvcZzKQ+UMlBwbknL5tIJE7KnN9ZEfNihVmyrMAzJAfe2PCyZAip/AkEA2esFkG+ScgeVYlGrUqrqUkvzj1j6F8R+8rGvCjq2WnDL8TzO7NoT7qivW/+6E9osX1WwWAtj/84eN7dvLLxCrQJBAN7GomZq58MzKIYPLH9iI3cwAJtn99ZfHKi9oipW9DBFW23TR6pTSDKlvVx0nwNzeEYFPOgqZstVhwZRR6kRawcCQHx/u0QTmjUvg/cR9bFbGFhAMDxbdzaQ+n4paXmMpZXyD3IZbZb/2JdnJBiJd4PUB7nHuOH0UANbfQQT9p42SFkCQQCcdFRTZEZv5TjmcUn0GBUzRmnswiRc1YEg81DSDlvD3dEIVSl6PLkzcNNItrgD5SfC5MxCv6PIUlJVhnkavEjS """ guard let privateDERData = Data(base64Encoded: privateDER) else { XCTFail("Failed to convert base64 string into data for decoding.") return } let decoded = try ASN1.Decoder.decode(data: privateDERData) // Ensure the first Node is of type SEQUENCE guard case .sequence(let nodes) = decoded else { XCTFail("Expected the top level node to be a sequence and it wasn't") return } // Ensure there are nine (9) Nodes within the top level SEQUENCE XCTAssertEqual(nodes.count, 9) // Deconstruct the parameters guard case .integer(let version) = nodes[0] else { XCTFail("Expected an integer within our sequence and it wasn't") return } XCTAssertEqual(version, Data(hex: "00")) guard case .integer(let n) = nodes[1] else { XCTFail("Expected an integer within our sequence and it wasn't") return } XCTAssertEqual(n, Data(hex: "00c19e66f206f38bf2280013c0a90acf683e3de35a67adebc64ff31272c6c6430254a9d467a8cf02dcd838a336e3de3dc8885fc58042fdb3823f044ae306ebe18c88c77581daff9972a7bca5133f053854a4d231dcadbe8db241840a297f51972778b7d51ba22cc87d1d6871ce455a9b3d4a9c38c2b93660b824511c8bfeaf75d3")) guard case .integer(let e) = nodes[2] else { XCTFail("Expected an integer within our sequence and it wasn't") return } XCTAssertEqual(e, Data(hex: "010001")) guard case .integer(let d) = nodes[3] else { XCTFail("Expected an integer within our sequence and it wasn't") return } XCTAssertEqual(d, Data(hex: "18990d2f165efe9a87266b5c009dd4f7c3608d6fc0d841a9f2224967b7851ca2412b4a46d91563a1b6fe8b0dc0294de41a1f40b228d09e6b9fa1e5f9adb96deffa238297d5852ecd1ec2828bc371ed4f766cd9cfd113f89a8829bf31965649d476fea35bb757f3714a804cb06cd29ae423d09355e29ea5cbdf780d8d674e87f1")) guard case .integer(let p) = nodes[4] else { XCTFail("Expected an integer within our sequence and it wasn't") return } XCTAssertEqual(p, Data(hex: "00e3744e2435d570280e7d75d5914a1bc988e30e1bcf938c4e47bdc673290f943250706e49cbe6d20913b2a737d6447cd8a1566cab300cc901f7b63c2c99022a7f")) guard case .integer(let q) = nodes[5] else { XCTFail("Expected an integer within our sequence and it wasn't") return } XCTAssertEqual(q, Data(hex: "00d9eb05906f927207956251ab52aaea524bf38f58fa17c47ef2b1af0a3ab65a70cbf13cceecda13eea8af5bffba13da2c5f55b0580b63ffce1e37b76f2cbc42ad")) guard case .integer(let exp1) = nodes[6] else { XCTFail("Expected an integer within our sequence and it wasn't") return } XCTAssertEqual(exp1, Data(hex: "00dec6a2666ae7c33328860f2c7f62237730009b67f7d65f1ca8bda22a56f430455b6dd347aa534832a5bd5c749f03737846053ce82a66cb5587065147a9116b07")) guard case .integer(let exp2) = nodes[7] else { XCTFail("Expected an integer within our sequence and it wasn't") return } XCTAssertEqual(exp2, Data(hex: "7c7fbb44139a352f83f711f5b15b185840303c5b773690fa7e2969798ca595f20f72196d96ffd897672418897783d407b9c7b8e1f450035b7d0413f69e364859")) guard case .integer(let coefficient) = nodes[8] else { XCTFail("Expected an integer within our sequence and it wasn't") return } XCTAssertEqual(coefficient, Data(hex: "009c74545364466fe538e67149f41815334669ecc2245cd58120f350d20e5bc3ddd10855297a3cb93370d348b6b803e527c2e4cc42bfa3c852525586791abc48d2")) // Ensure re-encoding the data yields the exact same starting data let asn: ASN1.Node = .sequence(nodes: [ .integer(data: version), .integer(data: n), .integer(data: e), .integer(data: d), .integer(data: p), .integer(data: q), .integer(data: exp1), .integer(data: exp2), .integer(data: coefficient) ]) // Encode the ASN1 Nodes let encodedData = ASN1.Encoder.encode(asn) // Ensure the re-encoded data matches the original data exactly XCTAssertEqual(Data(encodedData), privateDERData) XCTAssertEqual(encodedData, privateDERData.byteArray) XCTAssertEqual(encodedData.toBase64(), privateDER.replacingOccurrences(of: "\n", with: "")) } /// This tests decodes an Encrypted RSA Private Key from a Base64 PEM Encoded representation /// /// This test enforces that /// 1) The decoding process yields the expected format. /// 2) The re-encoding of the data yields the exact same starting data. func testASN1DecodingEncryptedPEM() throws { /// ========================== /// Encrypted PEM Structure /// ========================== /// /// EncryptedPrivateKey ::= SEQUENCE { /// /// PEMStructure ::= SEQUENCE { /// pemObjID OBJECTIDENTIFIER /// /// EncryptionAlgorithms ::= SEQUENCE { /// /// PBKDFAlgorithms ::= SEQUENCE { /// pbkdfObjID OBJECTIDENTIFIER /// PBKDFParams ::= SEQUENCE { /// salt OCTETSTRING, /// iterations INTEGER /// } /// }, /// /// CIPHERAlgorithms ::= SEQUENCE { /// cipherObjID OBJECTIDENTIFIER, /// iv OCTETSTRING /// } /// } /// } /// encryptedData OCTETSTRING /// } /// /// /* /// * Generated with /// * openssl genpkey -algorithm RSA /// * -pkeyopt rsa_keygen_bits:1024 /// * -pkeyopt rsa_keygen_pubexp:65537 /// * -out foo.pem /// * openssl pkcs8 -in foo.pem -topk8 -v2 aes-128-cbc -passout pass:mypassword /// */ let encryptedPEMFormat = """ MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIP5QK2RfqUl4CAggA MB0GCWCGSAFlAwQBAgQQj3OyM9gnW2dd/eRHkxjGrgSCAoCpM5GZB0v27cxzZsGc O4/xqgwB0c/bSJ6QogtYU2KVoc7ZNQ5q9jtzn3I4ONvneOkpm9arzYz0FWnJi2C3 BPiF0D1NkfvjvMLv56bwiG2A1oBECacyAb2pXYeJY7SdtYKvcbgs3jx65uCm6TF2 BylteH+n1ewTQN9DLfASp1n81Ajq9lQGaK03SN2MUtcAPp7N9gnxJrlmDGeqlPRs KpQYRcot+kE6Ew8a5jAr7mAxwpqvr3SM4dMvADZmRQsM4Uc/9+YMUdI52DG87EWc 0OUB+fnQ8jw4DZgOE9KKM5/QTWc3aEw/dzXr/YJsrv01oLazhqVHnEMG0Nfr0+DP q+qac1AsCsOb71VxaRlRZcVEkEfAq3gidSPD93qmlDrCnmLYTilcLanXUepda7ez qhjkHtpwBLN5xRZxOn3oUuLGjk8VRwfmFX+RIMYCyihjdmbEDYpNUVkQVYFGi/F/ 1hxOyl9yhGdL0hb9pKHH10GGIgoqo4jSTLlb4ennihGMHCjehAjLdx/GKJkOWShy V9hj8rAuYnRNb+tUW7ChXm1nLq14x9x1tX0ciVVn3ap/NoMkbFTr8M3pJ4bQlpAn wCT2erYqwQtgSpOJcrFeph9TjIrNRVE7Zlmr7vayJrB/8/oPssVdhf82TXkna4fB PcmO0YWLa117rfdeNM/Duy0ThSdTl39Qd+4FxqRZiHjbt+l0iSa/nOjTv1TZ/QqF wqrO6EtcM45fbFJ1Y79o2ptC2D6MB4HKJq9WCt064/8zQCVx3XPbb3X8Z5o/6koy ePGbz+UtSb9xczvqpRCOiFLh2MG1dUgWuHazjOtUcVWvilKnkjCMzZ9s1qG0sUDj nPyn """ guard let pemData = Data(base64Encoded: encryptedPEMFormat.replacingOccurrences(of: "\n", with: "")) else { XCTFail("Failed to convert base64 string to data") return } let asn = try ASN1.Decoder.decode(data: pemData) // Ensure the first node is a Sequence guard case .sequence(let encryptedPEMWrapper) = asn else { XCTFail("Expected top level Node to be a SEQUENCE object") return } // Ensure the first Sequence contains exactly 2 nodes (another Sequence and our OctetString of encrypted data) XCTAssertEqual(encryptedPEMWrapper.count, 2) // Ensure the first node within the top level sequence is another sequence guard case .sequence(let encryptionInfoWrapper) = encryptedPEMWrapper[0] else { XCTFail("Expected the first Node within our top level SEQUENCE to be a SEQUENCE object and it wasn't") return } // Ensure this sequence contains exactly two nodes (the PEMs ObjectIdentifier and another sequence that houses the encryption algorithms) XCTAssertEqual(encryptionInfoWrapper.count, 2) // Ensure the first Node is the PEM's OBJECTIDENTIFIER Node guard case .objectIdentifier(let pemObjID) = encryptionInfoWrapper[0] else { XCTFail("Expected an OBJECTIDENTIFIER and it wasn't") return } // Ensure the second Node is another SEQUENCE Node guard case .sequence(let encryptionAlgorithmsWrapper) = encryptionInfoWrapper[1] else { XCTFail("Expected another SEQUENCE Node and it wasn't") return } // Ensure this sequence contains exactly two nodes (the PEMs ObjectIdentifier and another sequence that houses the encryption algorithms) XCTAssertEqual(encryptionAlgorithmsWrapper.count, 2) // Ensure the first Node is another SEQUENCE Node guard case .sequence(let pbkdfAlgorithmWrapper) = encryptionAlgorithmsWrapper[0] else { XCTFail("Expected another SEQUENCE Node and it wasn't") return } // Ensure this sequence contains exactly two nodes (the PBKDF ObjectIdentifier and another sequence that houses the PBKDF params) XCTAssertEqual(pbkdfAlgorithmWrapper.count, 2) guard case .objectIdentifier(let pbkdfObjID) = pbkdfAlgorithmWrapper[0] else { XCTFail("Expected an OBJECTIDENTIFIER and it wasn't") return } guard case .sequence(let pbkdfParamsWrapper) = pbkdfAlgorithmWrapper[1] else { XCTFail("Expected an OCTETSTRING and it wasn't") return } // Ensure this sequence contains exactly two nodes (the PBKDF Salt as an OCTETSTRING and the PBKDF Iterations as an INTEGER) XCTAssertEqual(pbkdfParamsWrapper.count, 2) guard case .octetString(let pbkdfSalt) = pbkdfParamsWrapper[0] else { XCTFail("Expected an OCTETSTRING and it wasn't") return } guard case .integer(let pbkdfIterations) = pbkdfParamsWrapper[1] else { XCTFail("Expected an INTEGER and it wasn't") return } // Ensure the second Node is another SEQUENCE Node guard case .sequence(let cipherAlgorithmWrapper) = encryptionAlgorithmsWrapper[1] else { XCTFail("Expected another SEQUENCE Node and it wasn't") return } // Ensure this sequence contains exactly two nodes (the CIPHER ObjectIdentifier and an OCTETSTRING that contains the CIPHERs InitialVector) XCTAssertEqual(cipherAlgorithmWrapper.count, 2) guard case .objectIdentifier(let cipherObjID) = cipherAlgorithmWrapper[0] else { XCTFail("Expected an OBJECTIDENTIFIER and it wasn't") return } guard case .octetString(let cipherInitialVector) = cipherAlgorithmWrapper[1] else { XCTFail("Expected an OCTETSTRING and it wasn't") return } // Ensure the last (2nd) Node in the top level SEQUENCE Node is an OCTETSTRING that contains the encrypted key data guard case .octetString(let encryptedData) = encryptedPEMWrapper[1] else { XCTFail("Expected the last Node in the first SEQUENCE Node to be an OCTETSTRING and it wasn't") return } // Now lets ensure we can re encode the object and get back the exact same data let nodes: ASN1.Node = .sequence(nodes: [ .sequence(nodes: [ .objectIdentifier(data: pemObjID), .sequence(nodes: [ .sequence(nodes: [ .objectIdentifier(data: pbkdfObjID), .sequence(nodes: [ .octetString(data: pbkdfSalt), .integer(data: pbkdfIterations) ]) ]), .sequence(nodes: [ .objectIdentifier(data: cipherObjID), .octetString(data: cipherInitialVector) ]) ]) ]), .octetString(data: encryptedData) ]) // Encode the ASN1 Nodes let encodedData = ASN1.Encoder.encode(nodes) // Ensure the re-encoded data matches the original data exactly XCTAssertEqual(Data(encodedData), pemData) XCTAssertEqual(encodedData, pemData.byteArray) XCTAssertEqual(encodedData.toBase64(), encryptedPEMFormat.replacingOccurrences(of: "\n", with: "")) } static let allTests = [ ("testASN1NonDestructiveEncoding", testASN1NonDestructiveEncoding), ("testASN1DecodePrimitiveInteger", testASN1DecodePrimitiveInteger), ("testASN1DecodeLargeBigInteger", testASN1DecodeLargeBigInteger), ("testANS1DERDecodingPublicKey", testANS1DERDecodingPublicKey), ("testANS1DERDecodingPrivateKey", testANS1DERDecodingPrivateKey), ("testASN1DecodingEncryptedPEM", testASN1DecodingEncryptedPEM) ] } ================================================ FILE: Tests/CryptoSwiftTests/Access.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // import without @testable to test public API import CryptoSwift import Foundation import XCTest class Access: XCTestCase { let cipher = try! AES(key: "secret0key000000", iv: "0123456789012345") let authenticator = HMAC(key: Array(hex: "b1b2b3b3b3b3b3b3b1b2b3b3b3b3b3b3"), variant: .sha1) func testChecksum() { _ = Checksum.crc32([1, 2, 3]) _ = Checksum.crc32c([1, 2, 3]) _ = Checksum.crc16([1, 2, 3]) } func testRandomIV() { _ = AES.randomIV(AES.blockSize) _ = ChaCha20.randomIV(ChaCha20.blockSize) } func testDigest() { _ = Digest.md5([1, 2, 3]) _ = Digest.sha1([1, 2, 3]) _ = Digest.sha224([1, 2, 3]) _ = Digest.sha256([1, 2, 3]) _ = Digest.sha384([1, 2, 3]) _ = Digest.sha512([1, 2, 3]) _ = Digest.sha3([1, 2, 3], variant: .sha224) _ = SHA1().calculate(for: [0]) _ = SHA2(variant: .sha224).calculate(for: [0]) _ = SHA3(variant: .sha256).calculate(for: [0]) _ = MD5().calculate(for: [0]) } func testArrayExtension() { let array = Array(hex: "b1b2b3b3b3b3b3b3b1b2b3b3b3b3b3b3") _ = array.toHexString() _ = array.md5() _ = array.sha1() _ = array.sha256() _ = array.sha384() _ = array.sha512() _ = array.sha2(.sha224) _ = array.sha3(.sha224) _ = array.crc32() _ = array.crc32c() _ = array.crc16() do { _ = try array.encrypt(cipher: self.cipher) _ = try array.decrypt(cipher: self.cipher) _ = try array.authenticate(with: self.authenticator) } catch { XCTFail(error.localizedDescription) } } func testCollectionExtension() { // nothing public } func testStringExtension() { let string = "foofoobarbar" _ = string.md5() _ = string.sha1() _ = string.sha224() _ = string.sha256() _ = string.sha384() _ = string.sha512() _ = string.sha3(.sha224) _ = string.crc16() _ = string.crc32() _ = string.crc32c() do { _ = try string.encrypt(cipher: self.cipher) _ = try string.authenticate(with: self.authenticator) } catch { XCTFail(error.localizedDescription) } } func testStringFoundationExtension() { let string = "aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=" do { _ = try string.decryptBase64ToString(cipher: self.cipher) _ = try string.decryptBase64(cipher: self.cipher) } catch { XCTFail(error.localizedDescription) } } func testIntExtension() { // nothing public } func testUInt16Extension() { // nothing public } func testUInt32Extension() { // nothing public } func testUInt64Extension() { // nothing public } func testUInt8Extension() { // nothing public } func testDataExtension() { let data = Data( [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8]) _ = data.checksum() _ = data.md5() _ = data.sha1() _ = data.sha224() _ = data.sha256() _ = data.sha384() _ = data.sha512() _ = data.sha3(.sha224) _ = data.crc16() _ = data.crc32() _ = data.crc32c() _ = data.byteArray _ = data.toHexString() do { _ = try data.encrypt(cipher: self.cipher) _ = try data.decrypt(cipher: self.cipher) _ = try data.authenticate(with: self.authenticator) } catch { XCTFail(error.localizedDescription) } } func testPadding() { // PKCS7 _ = Padding.pkcs7.add(to: [1, 2, 3], blockSize: 16) _ = Padding.pkcs7.remove(from: [1, 2, 3], blockSize: 16) // PKCS5 _ = Padding.pkcs5.add(to: [1, 2, 3], blockSize: 16) _ = Padding.pkcs5.remove(from: [1, 2, 3], blockSize: 16) // NoPadding _ = Padding.noPadding.add(to: [1, 2, 3], blockSize: 16) _ = Padding.noPadding.remove(from: [1, 2, 3], blockSize: 16) // ZeroPadding _ = Padding.zeroPadding.add(to: [1, 2, 3], blockSize: 16) _ = Padding.zeroPadding.remove(from: [1, 2, 3], blockSize: 16) } func testPBKDF() { do { _ = PKCS5.PBKDF1.Variant.md5 _ = try PKCS5.PBKDF1(password: [1, 2, 3, 4, 5, 6, 7], salt: [1, 2, 3, 4, 5, 6, 7, 8]).calculate() _ = try PKCS5.PBKDF2(password: [1, 2, 3, 4, 5, 6, 7], salt: [1, 2, 3, 4]).calculate() } catch { XCTFail(error.localizedDescription) } } func testAuthenticators() { do { _ = try HMAC(key: Array(hex: "b1b2b3b3b3b3b3b3b1b2b3b3b3b3b3b3"), variant: .sha1).authenticate([1, 2, 3]) _ = try Poly1305(key: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2]).authenticate([1, 2, 3]) } catch { XCTFail(error.localizedDescription) } } func testAES() { do { let cipher = try AES(key: "secret0key000000", iv: "0123456789012345") var encryptor = try cipher.makeEncryptor() _ = try encryptor.update(withBytes: [1, 2, 3]) _ = try encryptor.finish() var decryptor = try cipher.makeDecryptor() _ = try decryptor.update(withBytes: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]) _ = try decryptor.finish() let enc = try cipher.encrypt([1, 2, 3]) _ = try cipher.decrypt(enc) _ = try AES(key: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6], blockMode: CBC(iv: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6]), padding: .noPadding) _ = AES.Variant.aes128 _ = AES.blockSize } catch { XCTFail("\(error)") } } func testBlowfish() { do { let cipher = try Blowfish(key: "secret0key000000", iv: "01234567") let enc = try cipher.encrypt([1, 2, 3]) _ = try cipher.decrypt(enc) _ = try Blowfish(key: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6], padding: .noPadding) _ = Blowfish.blockSize } catch { XCTFail(error.localizedDescription) } } func testRabbit() { do { let rabbit = try Rabbit(key: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) let enc = try rabbit.encrypt([1, 2, 3]) _ = try rabbit.decrypt(enc) XCTAssertThrowsError(try Rabbit(key: "123")) _ = Rabbit.blockSize _ = Rabbit.keySize _ = Rabbit.ivSize } catch { XCTFail(error.localizedDescription) } } func testChaCha20() { let key: Array = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] let iv: Array = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] do { _ = ChaCha20.blockSize let chacha20 = try ChaCha20(key: key, iv: iv) let enc = try chacha20.encrypt([1, 3, 4]) _ = try chacha20.decrypt(enc) XCTAssertThrowsError(try ChaCha20(key: "123", iv: "12345678")) _ = chacha20.makeEncryptor() _ = chacha20.makeDecryptor() } catch { XCTFail(error.localizedDescription) } } func testUpdatable() { // TODO: } static let allTests = [ ("testChecksum", testChecksum), ("testDigest", testDigest), ("testArrayExtension", testArrayExtension), ("testCollectionExtension", testCollectionExtension), ("testStringExtension", testStringExtension), ("testStringFoundationExtension", testStringFoundationExtension), ("testIntExtension", testIntExtension), ("testUInt16Extension", testUInt16Extension), ("testUInt32Extension", testUInt32Extension), ("testUInt64Extension", testUInt64Extension), ("testUInt8Extension", testUInt8Extension), ("testDataExtension", testDataExtension), ("testPadding", testPadding), ("testPBKDF", testPBKDF), ("testAuthenticators", testAuthenticators), ("testAES", testAES), ("testBlowfish", testBlowfish), ("testRabbit", testRabbit), ("testChaCha20", testChaCha20), ("testUpdatable", testUpdatable), ("testRandomIV", testRandomIV) ] } ================================================ FILE: Tests/CryptoSwiftTests/BlowfishTests.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // Test vector from http://www.schneier.com/code/vectors.txt import XCTest @testable import CryptoSwift class BlowfishTests: XCTestCase { struct TestData { let key: Array let input: Array let output: Array } let tests = [ TestData(key: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], input: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], output: [0x4e, 0xf9, 0x97, 0x45, 0x61, 0x98, 0xdd, 0x78]), TestData(key: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], input: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], output: [0x51, 0x86, 0x6f, 0xd5, 0xb8, 0x5e, 0xcb, 0x8a]), TestData(key: [0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], input: [0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01], output: [0x7d, 0x85, 0x6f, 0x9a, 0x61, 0x30, 0x63, 0xf2]), TestData(key: [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11], input: [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11], output: [0x24, 0x66, 0xdd, 0x87, 0x8b, 0x96, 0x3c, 0x9d]), TestData(key: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef], input: [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11], output: [0x61, 0xf9, 0xc3, 0x80, 0x22, 0x81, 0xb0, 0x96]), TestData(key: [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11], input: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef], output: [0x7d, 0x0c, 0xc6, 0x30, 0xaf, 0xda, 0x1e, 0xc7]), TestData(key: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], input: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], output: [0x4e, 0xf9, 0x97, 0x45, 0x61, 0x98, 0xdd, 0x78]), TestData(key: [0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10], input: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef], output: [0x0a, 0xce, 0xab, 0x0f, 0xc6, 0xa0, 0xa2, 0x8d]), TestData(key: [0x7c, 0xa1, 0x10, 0x45, 0x4a, 0x1a, 0x6e, 0x57], input: [0x01, 0xa1, 0xd6, 0xd0, 0x39, 0x77, 0x67, 0x42], output: [0x59, 0xc6, 0x82, 0x45, 0xeb, 0x05, 0x28, 0x2b]), TestData(key: [0x01, 0x31, 0xd9, 0x61, 0x9d, 0xc1, 0x37, 0x6e], input: [0x5c, 0xd5, 0x4c, 0xa8, 0x3d, 0xef, 0x57, 0xda], output: [0xb1, 0xb8, 0xcc, 0x0b, 0x25, 0x0f, 0x09, 0xa0]), TestData(key: [0x07, 0xa1, 0x13, 0x3e, 0x4a, 0x0b, 0x26, 0x86], input: [0x02, 0x48, 0xd4, 0x38, 0x06, 0xf6, 0x71, 0x72], output: [0x17, 0x30, 0xe5, 0x77, 0x8b, 0xea, 0x1d, 0xa4]), TestData(key: [0x38, 0x49, 0x67, 0x4c, 0x26, 0x02, 0x31, 0x9e], input: [0x51, 0x45, 0x4b, 0x58, 0x2d, 0xdf, 0x44, 0x0a], output: [0xa2, 0x5e, 0x78, 0x56, 0xcf, 0x26, 0x51, 0xeb]), TestData(key: [0x04, 0xb9, 0x15, 0xba, 0x43, 0xfe, 0xb5, 0xb6], input: [0x42, 0xfd, 0x44, 0x30, 0x59, 0x57, 0x7f, 0xa2], output: [0x35, 0x38, 0x82, 0xb1, 0x09, 0xce, 0x8f, 0x1a]), TestData(key: [0x01, 0x13, 0xb9, 0x70, 0xfd, 0x34, 0xf2, 0xce], input: [0x05, 0x9b, 0x5e, 0x08, 0x51, 0xcf, 0x14, 0x3a], output: [0x48, 0xf4, 0xd0, 0x88, 0x4c, 0x37, 0x99, 0x18]), TestData(key: [0x01, 0x70, 0xf1, 0x75, 0x46, 0x8f, 0xb5, 0xe6], input: [0x07, 0x56, 0xd8, 0xe0, 0x77, 0x47, 0x61, 0xd2], output: [0x43, 0x21, 0x93, 0xb7, 0x89, 0x51, 0xfc, 0x98]), TestData(key: [0x43, 0x29, 0x7f, 0xad, 0x38, 0xe3, 0x73, 0xfe], input: [0x76, 0x25, 0x14, 0xb8, 0x29, 0xbf, 0x48, 0x6a], output: [0x13, 0xf0, 0x41, 0x54, 0xd6, 0x9d, 0x1a, 0xe5]), TestData(key: [0x07, 0xa7, 0x13, 0x70, 0x45, 0xda, 0x2a, 0x16], input: [0x3b, 0xdd, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02], output: [0x2e, 0xed, 0xda, 0x93, 0xff, 0xd3, 0x9c, 0x79]), TestData(key: [0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd, 0x3b, 0x2f], input: [0x26, 0x95, 0x5f, 0x68, 0x35, 0xaf, 0x60, 0x9a], output: [0xd8, 0x87, 0xe0, 0x39, 0x3c, 0x2d, 0xa6, 0xe3]), TestData(key: [0x37, 0xd0, 0x6b, 0xb5, 0x16, 0xcb, 0x75, 0x46], input: [0x16, 0x4d, 0x5e, 0x40, 0x4f, 0x27, 0x52, 0x32], output: [0x5f, 0x99, 0xd0, 0x4f, 0x5b, 0x16, 0x39, 0x69]), TestData(key: [0x1f, 0x08, 0x26, 0x0d, 0x1a, 0xc2, 0x46, 0x5e], input: [0x6b, 0x05, 0x6e, 0x18, 0x75, 0x9f, 0x5c, 0xca], output: [0x4a, 0x05, 0x7a, 0x3b, 0x24, 0xd3, 0x97, 0x7b]), TestData(key: [0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76], input: [0x00, 0x4b, 0xd6, 0xef, 0x09, 0x17, 0x60, 0x62], output: [0x45, 0x20, 0x31, 0xc1, 0xe4, 0xfa, 0xda, 0x8e]), TestData(key: [0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xb0, 0x07], input: [0x48, 0x0d, 0x39, 0x00, 0x6e, 0xe7, 0x62, 0xf2], output: [0x75, 0x55, 0xae, 0x39, 0xf5, 0x9b, 0x87, 0xbd]), TestData(key: [0x49, 0x79, 0x3e, 0xbc, 0x79, 0xb3, 0x25, 0x8f], input: [0x43, 0x75, 0x40, 0xc8, 0x69, 0x8f, 0x3c, 0xfa], output: [0x53, 0xc5, 0x5f, 0x9c, 0xb4, 0x9f, 0xc0, 0x19]), TestData(key: [0x4f, 0xb0, 0x5e, 0x15, 0x15, 0xab, 0x73, 0xa7], input: [0x07, 0x2d, 0x43, 0xa0, 0x77, 0x07, 0x52, 0x92], output: [0x7a, 0x8e, 0x7b, 0xfa, 0x93, 0x7e, 0x89, 0xa3]), TestData(key: [0x49, 0xe9, 0x5d, 0x6d, 0x4c, 0xa2, 0x29, 0xbf], input: [0x02, 0xfe, 0x55, 0x77, 0x81, 0x17, 0xf1, 0x2a], output: [0xcf, 0x9c, 0x5d, 0x7a, 0x49, 0x86, 0xad, 0xb5]), TestData(key: [0x01, 0x83, 0x10, 0xdc, 0x40, 0x9b, 0x26, 0xd6], input: [0x1d, 0x9d, 0x5c, 0x50, 0x18, 0xf7, 0x28, 0xc2], output: [0xd1, 0xab, 0xb2, 0x90, 0x65, 0x8b, 0xc7, 0x78]), TestData(key: [0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef], input: [0x30, 0x55, 0x32, 0x28, 0x6d, 0x6f, 0x29, 0x5a], output: [0x55, 0xcb, 0x37, 0x74, 0xd1, 0x3e, 0xf2, 0x01]), TestData(key: [0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01], input: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef], output: [0xfa, 0x34, 0xec, 0x48, 0x47, 0xb2, 0x68, 0xb2]), TestData(key: [0x1f, 0x1f, 0x1f, 0x1f, 0x0e, 0x0e, 0x0e, 0x0e], input: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef], output: [0xa7, 0x90, 0x79, 0x51, 0x08, 0xea, 0x3c, 0xae]), TestData(key: [0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1, 0xfe], input: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef], output: [0xc3, 0x9e, 0x07, 0x2d, 0x9f, 0xac, 0x63, 0x1d]), TestData(key: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], input: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], output: [0x01, 0x49, 0x33, 0xe0, 0xcd, 0xaf, 0xf6, 0xe4]), TestData(key: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], input: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], output: [0xf2, 0x1e, 0x9a, 0x77, 0xb7, 0x1c, 0x49, 0xbc]), TestData(key: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef], input: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], output: [0x24, 0x59, 0x46, 0x88, 0x57, 0x54, 0x36, 0x9a]), TestData(key: [0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10], input: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], output: [0x6b, 0x5c, 0x5a, 0x9c, 0x5d, 0x9e, 0x0a, 0x5a]) ] func testEncrypt() { for test in self.tests { XCTAssertEqual(try Blowfish(key: test.key, blockMode: ECB(), padding: .noPadding).encrypt(test.input), test.output) } } func testDecrypt() { for test in self.tests { XCTAssertEqual(try Blowfish(key: test.key, blockMode: ECB(), padding: .noPadding).decrypt(test.output), test.input) } } func testCBCZeroPadding() { let key = Array(hex: "0123456789ABCDEFF0E1D2C3B4A59687") let iv = Array(hex: "FEDCBA9876543210") let input = Array(hex: "37363534333231204E6F77206973207468652074696D6520666F722000") XCTAssertEqual(try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .zeroPadding).encrypt(input), Array(hex: "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC")) } func testEncryptDecrypt() { let key = Array.init(hex: "0123456789ABCDEFF0E1D2C3B4A59687") let iv = Array.init(hex: "FEDCBA9876543210") let input = Array.init(hex: "37363534333231204E6F77206973207468652074696D6520666F722000") do { let cipher = try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .pkcs7) let ciphertext = try cipher.encrypt(input) let plaintext = try cipher.decrypt(ciphertext) XCTAssertEqual(plaintext, input) } catch { XCTFail(error.localizedDescription) } } // https://github.com/krzyzanowskim/CryptoSwift/issues/415 func testDecryptCFB415() { do { let plaintext = "secret12".bytes let key = "passwordpassword".bytes let iv = "12345678".bytes let encrypted = try Blowfish(key: key, blockMode: CFB(iv: iv), padding: .noPadding).encrypt(plaintext) let decrypted = try Blowfish(key: key, blockMode: CFB(iv: iv), padding: .noPadding).decrypt(encrypted) XCTAssertEqual(plaintext, decrypted) } catch { XCTFail(error.localizedDescription) } } } extension BlowfishTests { static func allTests() -> [(String, (BlowfishTests) -> () -> Void)] { let tests = [ ("testEncrypt", testEncrypt), ("testDecrypt", testDecrypt), ("testCBCZeroPadding", testCBCZeroPadding), ("testEncryptDecrypt", testEncryptDecrypt), ("testDecryptCFB415", testDecryptCFB415) ] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/Bridging.h ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // #ifndef CryptoSwift_Bridging_h #define CryptoSwift_Bridging_h #import #endif ================================================ FILE: Tests/CryptoSwiftTests/CBCMacTests.swift ================================================ //// CryptoSwift // // Copyright (C) 2014-__YEAR__ Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import XCTest @testable import CryptoSwift class CBCMacTests: XCTestCase { func testMessageLength0() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let msg: Array = [] let expectedMac: Array = [0xf6, 0xc7, 0x1e, 0xed, 0xc3, 0xd9, 0x9b, 0xb1, 0x83, 0xcb, 0x5b, 0x8d, 0x15, 0x68, 0xe6, 0x06] let cbcmac = try! CBCMAC(key: key).authenticate(msg) XCTAssertEqual(cbcmac, expectedMac, "Invalid authentication result") } func testMessageLength16() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let msg: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a] let expectedMac: Array = [0x05, 0x39, 0xbd, 0xa3, 0x0b, 0x3f, 0x76, 0x34, 0x46, 0x6a, 0x75, 0xd9, 0x84, 0x18, 0xbf, 0x65] let cbcmac = try! CBCMAC(key: key).authenticate(msg) XCTAssertEqual(cbcmac, expectedMac, "Invalid authentication result") } func testMessageLength40() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let msg: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11] let expectedMac: Array = [0xa5, 0x26, 0x0f, 0x98, 0xf1, 0xab, 0xf2, 0xb2, 0x75, 0x62, 0xed, 0x5f, 0xc1, 0xfb, 0xeb, 0x8d] let cbcmac = try! CBCMAC(key: key).authenticate(msg) XCTAssertEqual(cbcmac, expectedMac, "Invalid authentication result") } func testMessageLength64() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let msg: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10] let expectedMac: Array = [0x5b, 0xf8, 0x2f, 0x1f, 0xe7, 0x48, 0x3b, 0x9a, 0x87, 0x5c, 0xaf, 0x3d, 0xed, 0x3a, 0x01, 0x71] let cbcmac = try! CBCMAC(key: key).authenticate(msg) XCTAssertEqual(cbcmac, expectedMac, "Invalid authentication result") } static let allTests = [ ("testMessageLength0", testMessageLength0), ("testMessageLength16", testMessageLength16), ("testMessageLength40", testMessageLength40), ("testMessageLength64", testMessageLength64) ] } ================================================ FILE: Tests/CryptoSwiftTests/CMACTests.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // Test vectors from https://tools.ietf.org/html/rfc4493 // Text vectors from http://www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/tv/omac1-tv.txt import XCTest @testable import CryptoSwift final class CMACTests: XCTestCase { func testMessageLength0() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let msg: Array = [] let expectedMac: Array = [0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46] let cmac = try! CMAC(key: key).authenticate(msg) XCTAssertEqual(cmac, expectedMac, "Invalid authentication result") } func testMessageLength16() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let msg: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a] let expectedMac: Array = [0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c] let cmac = try! CMAC(key: key).authenticate(msg) XCTAssertEqual(cmac, expectedMac, "Invalid authentication result") } func testMessageLength40() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let msg: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11] let expectedMac: Array = [0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27] let cmac = try! CMAC(key: key).authenticate(msg) XCTAssertEqual(cmac, expectedMac, "Invalid authentication result") } func testMessageLength64() { let key: Array = [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] let msg: Array = [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10] let expectedMac: Array = [0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe] let cmac = try! CMAC(key: key).authenticate(msg) XCTAssertEqual(cmac, expectedMac, "Invalid authentication result") } func testOMACTextVectors() { // Test vectors: http://www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/tv/omac1-tv.txt let vectors: [(key: [UInt8], msg: [UInt8], cmac: [UInt8])] = [ // AES-192 (key: [0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b], msg: [], cmac: [0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67]), (key: [0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b], msg: [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a], cmac: [0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84]), (key: [0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b], msg: [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11], cmac: [0x8a, 0x1d, 0xe5, 0xbe, 0x2e, 0xb3, 0x1a, 0xad, 0x08, 0x9a, 0x82, 0xe6, 0xee, 0x90, 0x8b, 0x0e]), (key: [0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b], msg: [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10], cmac: [0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11]), // AES-256 (key: [0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4], msg: [], cmac: [0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83]), (key: [0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4], msg: [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a], cmac: [0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c]), (key: [0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4], msg: [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11], cmac: [0xaa, 0xf3, 0xd8, 0xf1, 0xde, 0x56, 0x40, 0xc2, 0x32, 0xf5, 0xb1, 0x69, 0xb9, 0xc9, 0x11, 0xe6]), (key: [0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4], msg: [0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10], cmac: [0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10]), ] for v in vectors { let cmac = try! CMAC(key: v.key).authenticate(v.msg) XCTAssertEqual(cmac, v.cmac, "Failed \(v)") } } static let allTests = [ ("testMessageLength0", testMessageLength0), ("testMessageLength16", testMessageLength16), ("testMessageLength40", testMessageLength40), ("testMessageLength64", testMessageLength64), ("testOMACTextVectors", testOMACTextVectors) ] } ================================================ FILE: Tests/CryptoSwiftTests/ChaCha20Poly1305Tests.swift ================================================ // // ChaCha20Poly1305Tests.swift // CryptoSwiftTests // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // // https://tools.ietf.org/html/rfc7539#section-2.8.1 import XCTest @testable import CryptoSwift class ChaCha20Poly1305Tests: XCTestCase { static let allTests = [ ("testCCPoly1", test1), ("testCCPoly2", test2), ("testCCPoly3", test3) ] func test1() { self.executeTestCase("6b65792e6b65792e6b65792e6b65792e6b65792e6b65792e6b65792e6b65792e", "6e6f6e63652e6e6f6e63652e", "", "6d657373616765", "5d9c0a9fe7d5e5", "c93aa61fc3cc66a819ac96f6ce365aee") } func test2() { /* Test vector from section 2.8.2. */ self.executeTestCase("808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", "070000004041424344454647", "50515253c0c1c2c3c4c5c6c7", "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e", "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116", "1ae10b594f09e26a7e902ecbd0600691") } func test3() { /* Test vector from A.5. */ self.executeTestCase("1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0", "000000000102030405060708", "f33388860000000000004e91", "496e7465726e65742d4472616674732061726520647261667420646f63756d656e74732076616c696420666f722061206d6178696d756d206f6620736978206d6f6e74687320616e64206d617920626520757064617465642c207265706c616365642c206f72206f62736f6c65746564206279206f7468657220646f63756d656e747320617420616e792074696d652e20497420697320696e617070726f70726961746520746f2075736520496e7465726e65742d447261667473206173207265666572656e6365206d6174657269616c206f7220746f2063697465207468656d206f74686572207468616e206173202fe2809c776f726b20696e2070726f67726573732e2fe2809d", "64a0861575861af460f062c79be643bd5e805cfd345cf389f108670ac76c8cb24c6cfc18755d43eea09ee94e382d26b0bdb7b73c321b0100d4f03b7f355894cf332f830e710b97ce98c8a84abd0b948114ad176e008d33bd60f982b1ff37c8559797a06ef4f0ef61c186324e2b3506383606907b6a7c02b0f9f6157b53c867e4b9166c767b804d46a59b5216cde7a4e99040c5a40433225ee282a1b0a06c523eaf4534d7f83fa1155b0047718cbc546a0d072b04b3564eea1b422273f548271a0bb2316053fa76991955ebd63159434ecebb4e466dae5a1073a6727627097a1049e617d91d361094fa68f0ff77987130305beaba2eda04df997b714d6c6f2c29a6ad5cb4022b02709b", "eead9d67890cbb22392336fea1851f38") } func executeTestCase(_ key: String, _ nonce: String, _ header: String, _ message: String, _ cipher: String, _ tag: String) { let keyArr = Array(hex: key) let nonceArr = Array(hex: nonce) let headerArr = Array(hex: header) let messageArr = Array(hex: message) let cipherArr = Array(hex: cipher) let tagArr = Array(hex: tag) do { let encryptResult = try AEADChaCha20Poly1305.encrypt(messageArr, key: keyArr, iv: nonceArr, authenticationHeader: headerArr) XCTAssertEqual(encryptResult.cipherText, cipherArr, "cipher not equal") XCTAssertEqual(encryptResult.authenticationTag, tagArr, "tag not equal") } catch { XCTAssert(false, "Encryption Failed with error: \(error.localizedDescription)") } do { let decryptResult = try AEADChaCha20Poly1305.decrypt(cipherArr, key: keyArr, iv: nonceArr, authenticationHeader: headerArr, authenticationTag: tagArr) XCTAssertEqual(decryptResult.success, true, "decrypt mac check failed") XCTAssertEqual(decryptResult.plainText, messageArr, "message not equal") } catch { XCTAssert(false, "Encryption Failed with error: \(error.localizedDescription)") } } } ================================================ FILE: Tests/CryptoSwiftTests/ChaCha20Tests.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation import XCTest @testable import CryptoSwift final class ChaCha20Tests: XCTestCase { func testChaCha20() { let keys: [Array] = [ [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f] ] let ivs: [Array] = [ [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01], [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07] ] let expectedHexes = [ "76B8E0ADA0F13D90405D6AE55386BD28BDD219B8A08DED1AA836EFCC8B770DC7DA41597C5157488D7724E03FB8D84A376A43B8F41518A11CC387B669B2EE6586", "4540F05A9F1FB296D7736E7B208E3C96EB4FE1834688D2604F450952ED432D41BBE2A0B6EA7566D2A5D1E7E20D42AF2C53D792B1C43FEA817E9AD275AE546963", "DE9CBA7BF3D69EF5E786DC63973F653A0B49E015ADBFF7134FCB7DF137821031E85A050278A7084527214F73EFC7FA5B5277062EB7A0433E445F41E3", "EF3FDFD6C61578FBF5CF35BD3DD33B8009631634D21E42AC33960BD138E50D32111E4CAF237EE53CA8AD6426194A88545DDC497A0B466E7D6BBDB0041B2F586B", "F798A189F195E66982105FFB640BB7757F579DA31602FC93EC01AC56F85AC3C134A4547B733B46413042C9440049176905D3BE59EA1C53F15916155C2BE8241A38008B9A26BC35941E2444177C8ADE6689DE95264986D95889FB60E84629C9BD9A5ACB1CC118BE563EB9B3A4A472F82E09A7E778492B562EF7130E88DFE031C79DB9D4F7C7A899151B9A475032B63FC385245FE054E3DD5A97A5F576FE064025D3CE042C566AB2C507B138DB853E3D6959660996546CC9C4A6EAFDC777C040D70EAF46F76DAD3979E5C5360C3317166A1C894C94A371876A94DF7628FE4EAAF2CCB27D5AAAE0AD7AD0F9D4B6AD3B54098746D4524D38407A6DEB3AB78FAB78C9" ] for idx in 0..(repeating: 0, count: expectedHex.count / 2) do { let encrypted = try message.encrypt(cipher: ChaCha20(key: keys[idx], iv: ivs[idx])) let decrypted = try encrypted.decrypt(cipher: ChaCha20(key: keys[idx], iv: ivs[idx])) XCTAssertEqual(message, decrypted, "ChaCha20 decryption failed") XCTAssertEqual(encrypted, Array(hex: expectedHex)) } catch CipherError.encrypt { XCTAssert(false, "Encryption failed") } catch CipherError.decrypt { XCTAssert(false, "Decryption failed") } catch { XCTAssert(false, "Failed") } } } func testCore() { let key: Array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31] var counter: Array = [1, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 74, 0, 0, 0, 0] let input = Array.init(repeating: 0, count: 129) let chacha = try! ChaCha20(key: key, iv: Array(key[4..<16])) let result = chacha.process(bytes: input.slice, counter: &counter, key: key) XCTAssertEqual(result.toHexString(), "10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4ed2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e0a88837739d7bf4ef8ccacb0ea2bb9d69d56c394aa351dfda5bf459f0a2e9fe8e721f89255f9c486bf21679c683d4f9c5cf2fa27865526005b06ca374c86af3bdc") } func testVector1Py() { let key: Array = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] let iv: Array = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] let expected: Array = [0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d, 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c, 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86] let message = Array(repeating: 0, count: expected.count) do { let encrypted = try ChaCha20(key: key, iv: iv).encrypt(message) XCTAssertEqual(encrypted, expected, "Ciphertext failed") } catch { XCTFail() } } func testChaCha20EncryptPartial() { let key: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07] let expectedHex = "F798A189F195E66982105FFB640BB7757F579DA31602FC93EC01AC56F85AC3C134A4547B733B46413042C9440049176905D3BE59EA1C53F15916155C2BE8241A38008B9A26BC35941E2444177C8ADE6689DE95264986D95889FB60E84629C9BD9A5ACB1CC118BE563EB9B3A4A472F82E09A7E778492B562EF7130E88DFE031C79DB9D4F7C7A899151B9A475032B63FC385245FE054E3DD5A97A5F576FE064025D3CE042C566AB2C507B138DB853E3D6959660996546CC9C4A6EAFDC777C040D70EAF46F76DAD3979E5C5360C3317166A1C894C94A371876A94DF7628FE4EAAF2CCB27D5AAAE0AD7AD0F9D4B6AD3B54098746D4524D38407A6DEB3AB78FAB78C9" let plaintext: Array = Array(repeating: 0, count: expectedHex.count / 2) do { let cipher = try ChaCha20(key: key, iv: iv) var ciphertext = Array() var encryptor = cipher.makeEncryptor() ciphertext += try encryptor.update(withBytes: Array(plaintext[0..<8])) ciphertext += try encryptor.update(withBytes: Array(plaintext[8..<16])) ciphertext += try encryptor.update(withBytes: Array(plaintext[16..<80])) ciphertext += try encryptor.update(withBytes: Array(plaintext[80..<256])) ciphertext += try encryptor.finish() XCTAssertEqual(Array(hex: expectedHex), ciphertext) } catch { XCTFail() } } } extension ChaCha20Tests { static func allTests() -> [(String, (ChaCha20Tests) -> () -> Void)] { let tests = [ ("testChaCha20", testChaCha20), ("testCore", testCore), ("testVector1Py", testVector1Py), ("testChaCha20EncryptPartial", testChaCha20EncryptPartial) ] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/ChaCha20TestsPerf.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation import XCTest @testable import CryptoSwift final class ChaCha20TestsPerf: XCTestCase { func testChaCha20Performance() { let key: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f] let iv: Array = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07] let message = Array(repeating: 7, count: 1024 * 1024) measureMetrics([XCTPerformanceMetric.wallClockTime], automaticallyStartMeasuring: true) { () -> Void in do { _ = try ChaCha20(key: key, iv: iv).encrypt(message) } catch { XCTFail() } self.stopMeasuring() } } } extension ChaCha20TestsPerf { static func allTests() -> [(String, (ChaCha20TestsPerf) -> () -> Void)] { let tests = [("testChaCha20Performance", testChaCha20Performance)] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/DigestTests.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // http://www.di-mgt.com.au/sha_testvectors.html (http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf) // import Foundation import XCTest @testable import CryptoSwift final class DigestTests: XCTestCase { func testMD5() { XCTAssertEqual("123".md5(), "202cb962ac59075b964b07152d234b70", "MD5 calculation failed") XCTAssertEqual("".md5(), "d41d8cd98f00b204e9800998ecf8427e", "MD5 calculation failed") XCTAssertEqual("a".md5(), "0cc175b9c0f1b6a831c399e269772661", "MD5 calculation failed") XCTAssertEqual("abc".md5(), "900150983cd24fb0d6963f7d28e17f72", "MD5 calculation failed") XCTAssertEqual("message digest".md5(), "f96b697d7cb7938d525a2f31aaf161d0", "MD5 calculation failed") XCTAssertEqual("abcdefghijklmnopqrstuvwxyz".md5(), "c3fcd3d76192e4007dfb496cca67e13b", "MD5 calculation failed") XCTAssertEqual("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".md5(), "d174ab98d277d9f5a5611c2c9f419d9f", "MD5 calculation failed") XCTAssertEqual("12345678901234567890123456789012345678901234567890123456789012345678901234567890".md5(), "57edf4a22be3c955ac49da2e2107b67a", "MD5 calculation failed") } func testSHA1() { XCTAssertEqual(SHA1().calculate(for: Array(hex: "616263")).toHexString(), "a9993e364706816aba3e25717850c26c9cd0d89d") XCTAssertEqual(SHA1().calculate(for: Array(hex: "")).toHexString(), "da39a3ee5e6b4b0d3255bfef95601890afd80709") XCTAssertEqual("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha1(), "84983e441c3bd26ebaae4aa1f95129e5e54670f1") XCTAssertEqual("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".sha1(), "a49b2446a02c645bf419f995b67091253a04a259") XCTAssertEqual(Array(repeating: 0x61, count: 1_000_000).sha1(), Array(hex: "34aa973cd4c4daa4f61eeb2bdbad27316534016f"), "One million (1,000,000) repetitions of the character 'a' (0x61)") // https://github.com/krzyzanowskim/CryptoSwift/issues/363 XCTAssertEqual("1477304791&1XpnGSRhOlZz2etXMeOdfNaHILTjW16U&8mpBBbzwsgs".sha1(), "0809bbf8489c594131c2030a84be364a0851a635", "Failed") XCTAssertEqual("1477304791&1XpnGSRhOlZz2etXMeOdfNaHILTjW16U&8mpBBbzwsgsa".sha1(), "d345b525ebada7becc8107c54e07fa88644471f5", "Failed") XCTAssertEqual("1477304791&1XpnGSRhOlZz2etXMeOdfNaHILTjW16U&8mpBBbzwsg".sha1(), "c106aa0a98606294ee35fd2d937e928ebb5339e0", "Failed") } func testSHA2() { XCTAssertEqual(SHA2(variant: .sha224).calculate(for: Array(hex: "616263")).toHexString(), "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7") XCTAssertEqual(SHA2(variant: .sha256).calculate(for: Array(hex: "616263")).toHexString(), "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") XCTAssertEqual(SHA2(variant: .sha384).calculate(for: Array(hex: "616263")).toHexString(), "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7") XCTAssertEqual(SHA2(variant: .sha512).calculate(for: Array(hex: "616263")).toHexString(), "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f") XCTAssertEqual(SHA2(variant: .sha224).calculate(for: Array(hex: "")).toHexString(), "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f") XCTAssertEqual(SHA2(variant: .sha256).calculate(for: Array(hex: "")).toHexString(), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") XCTAssertEqual(SHA2(variant: .sha384).calculate(for: Array(hex: "")).toHexString(), "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b") XCTAssertEqual(SHA2(variant: .sha512).calculate(for: Array(hex: "")).toHexString(), "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e") XCTAssertEqual("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha224(), "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525") XCTAssertEqual("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha256(), "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1") XCTAssertEqual("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha384(), "3391fdddfc8dc7393707a65b1b4709397cf8b1d162af05abfe8f450de5f36bc6b0455a8520bc4e6f5fe95b1fe3c8452b") XCTAssertEqual("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha512(), "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445") XCTAssertEqual("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".sha224(), "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3") XCTAssertEqual("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".sha256(), "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1") XCTAssertEqual("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".sha384(), "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039") XCTAssertEqual("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".sha512(), "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909") XCTAssertEqual(Array(repeating: 0x61, count: 1_000_000).sha224(), Array(hex: "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67"), "One million (1,000,000) repetitions of the character 'a' (0x61)") XCTAssertEqual(Array(repeating: 0x61, count: 1_000_000).sha256(), Array(hex: "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"), "One million (1,000,000) repetitions of the character 'a' (0x61)") XCTAssertEqual(Array(repeating: 0x61, count: 1_000_000).sha384(), Array(hex: "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985"), "One million (1,000,000) repetitions of the character 'a' (0x61)") XCTAssertEqual(Array(repeating: 0x61, count: 1_000_000).sha512(), Array(hex: "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"), "One million (1,000,000) repetitions of the character 'a' (0x61)") XCTAssertEqual("Rosetta code".sha256(), "764faf5c61ac315f1497f9dfa542713965b785e5cc2f707d6468d7d1124cdfcf", "SHA256 calculation failed") XCTAssertEqual("The quick brown fox jumps over the lazy dog.".sha384(), "ed892481d8272ca6df370bf706e4d7bc1b5739fa2177aae6c50e946678718fc67a7af2819a021c2fc34e91bdb63409d7", "SHA384 calculation failed") } func testSHA3() { XCTAssertEqual(SHA3(variant: .sha224).calculate(for: Array(hex: "616263")).toHexString(), "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf") XCTAssertEqual(SHA3(variant: .sha256).calculate(for: Array(hex: "616263")).toHexString(), "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532") XCTAssertEqual(SHA3(variant: .sha384).calculate(for: Array(hex: "616263")).toHexString(), "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25") XCTAssertEqual(SHA3(variant: .sha512).calculate(for: Array(hex: "616263")).toHexString(), "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0") XCTAssertEqual(SHA3(variant: .keccak224).calculate(for: Array(hex: "616263")).toHexString(), "c30411768506ebe1c2871b1ee2e87d38df342317300a9b97a95ec6a8") XCTAssertEqual(SHA3(variant: .keccak256).calculate(for: Array(hex: "616263")).toHexString(), "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45") XCTAssertEqual(SHA3(variant: .keccak384).calculate(for: Array(hex: "616263")).toHexString(), "f7df1165f033337be098e7d288ad6a2f74409d7a60b49c36642218de161b1f99f8c681e4afaf31a34db29fb763e3c28e") XCTAssertEqual(SHA3(variant: .keccak512).calculate(for: Array(hex: "616263")).toHexString(), "18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96") XCTAssertEqual(SHA3(variant: .sha224).calculate(for: Array(hex: "")).toHexString(), "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7") XCTAssertEqual(SHA3(variant: .sha256).calculate(for: Array(hex: "")).toHexString(), "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a") XCTAssertEqual(SHA3(variant: .sha384).calculate(for: Array(hex: "")).toHexString(), "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004") XCTAssertEqual(SHA3(variant: .sha512).calculate(for: Array(hex: "")).toHexString(), "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26") XCTAssertEqual(SHA3(variant: .keccak224).calculate(for: Array(hex: "")).toHexString(), "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd") XCTAssertEqual(SHA3(variant: .keccak256).calculate(for: Array(hex: "")).toHexString(), "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") XCTAssertEqual(SHA3(variant: .keccak384).calculate(for: Array(hex: "")).toHexString(), "2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff") XCTAssertEqual(SHA3(variant: .keccak512).calculate(for: Array(hex: "")).toHexString(), "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e") XCTAssertEqual("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha3(.sha224), "8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33") XCTAssertEqual("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha3(.sha256), "41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376") XCTAssertEqual("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha3(.sha384), "991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5aa04a1f076e62fea19eef51acd0657c22") XCTAssertEqual("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha3(.sha512), "04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636dee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e") XCTAssertEqual("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha3(.keccak224), "e51faa2b4655150b931ee8d700dc202f763ca5f962c529eae55012b6") XCTAssertEqual("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha3(.keccak256), "45d3b367a6904e6e8d502ee04999a7c27647f91fa845d456525fd352ae3d7371") XCTAssertEqual("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha3(.keccak384), "b41e8896428f1bcbb51e17abd6acc98052a3502e0d5bf7fa1af949b4d3c855e7c4dc2c390326b3f3e74c7b1e2b9a3657") XCTAssertEqual("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".sha3(.keccak512), "6aa6d3669597df6d5a007b00d09c20795b5c4218234e1698a944757a488ecdc09965435d97ca32c3cfed7201ff30e070cd947f1fc12b9d9214c467d342bcba5d") XCTAssertEqual("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".sha3(.sha224), "543e6868e1666c1a643630df77367ae5a62a85070a51c14cbf665cbc") XCTAssertEqual("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".sha3(.sha256), "916f6061fe879741ca6469b43971dfdb28b1a32dc36cb3254e812be27aad1d18") XCTAssertEqual("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".sha3(.sha384), "79407d3b5916b59c3e30b09822974791c313fb9ecc849e406f23592d04f625dc8c709b98b43b3852b337216179aa7fc7") XCTAssertEqual("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".sha3(.sha512), "afebb2ef542e6579c50cad06d2e578f9f8dd6881d7dc824d26360feebf18a4fa73e3261122948efcfd492e74e82e2189ed0fb440d187f382270cb455f21dd185") XCTAssertEqual("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".sha3(.keccak224), "344298994b1b06873eae2ce739c425c47291a2e24189e01b524f88dc") XCTAssertEqual("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".sha3(.keccak256), "f519747ed599024f3882238e5ab43960132572b7345fbeb9a90769dafd21ad67") XCTAssertEqual("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".sha3(.keccak384), "cc063f34685135368b34f7449108f6d10fa727b09d696ec5331771da46a923b6c34dbd1d4f77e595689c1f3800681c28") XCTAssertEqual("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu".sha3(.keccak512), "ac2fb35251825d3aa48468a9948c0a91b8256f6d97d8fa4160faff2dd9dfcc24f3f1db7a983dad13d53439ccac0b37e24037e7b95f80f59f37a2f683c4ba4682") XCTAssertEqual(Array(repeating: 0x61, count: 1_000_000).sha3(.sha224), Array(hex: "d69335b93325192e516a912e6d19a15cb51c6ed5c15243e7a7fd653c"), "One million (1,000,000) repetitions of the character 'a' (0x61)") XCTAssertEqual(Array(repeating: 0x61, count: 1_000_000).sha3(.sha256), Array(hex: "5c8875ae474a3634ba4fd55ec85bffd661f32aca75c6d699d0cdcb6c115891c1"), "One million (1,000,000) repetitions of the character 'a' (0x61)") XCTAssertEqual(Array(repeating: 0x61, count: 1_000_000).sha3(.sha384), Array(hex: "eee9e24d78c1855337983451df97c8ad9eedf256c6334f8e948d252d5e0e76847aa0774ddb90a842190d2c558b4b8340"), "One million (1,000,000) repetitions of the character 'a' (0x61)") XCTAssertEqual(Array(repeating: 0x61, count: 1_000_000).sha3(.sha512), Array(hex: "3c3a876da14034ab60627c077bb98f7e120a2a5370212dffb3385a18d4f38859ed311d0a9d5141ce9cc5c66ee689b266a8aa18ace8282a0e0db596c90b0a7b87"), "One million (1,000,000) repetitions of the character 'a' (0x61)") XCTAssertEqual(Array(repeating: 0x61, count: 1_000_000).sha3(.keccak224), Array(hex: "19f9167be2a04c43abd0ed554788101b9c339031acc8e1468531303f"), "One million (1,000,000) repetitions of the character 'a' (0x61)") XCTAssertEqual(Array(repeating: 0x61, count: 1_000_000).sha3(.keccak256), Array(hex: "fadae6b49f129bbb812be8407b7b2894f34aecf6dbd1f9b0f0c7e9853098fc96"), "One million (1,000,000) repetitions of the character 'a' (0x61)") XCTAssertEqual(Array(repeating: 0x61, count: 1_000_000).sha3(.keccak384), Array(hex: "0c8324e1ebc182822c5e2a086cac07c2fe00e3bce61d01ba8ad6b71780e2dec5fb89e5ae90cb593e57bc6258fdd94e17"), "One million (1,000,000) repetitions of the character 'a' (0x61)") XCTAssertEqual(Array(repeating: 0x61, count: 1_000_000).sha3(.keccak512), Array(hex: "5cf53f2e556be5a624425ede23d0e8b2c7814b4ba0e4e09cbbf3c2fac7056f61e048fc341262875ebc58a5183fea651447124370c1ebf4d6c89bc9a7731063bb"), "One million (1,000,000) repetitions of the character 'a' (0x61)") // *** Multiple of block size *** // keccak block size bytes XCTAssertEqual(Array(repeating: 0x00, count: 144).sha3(.keccak224), Array(hex: "a50976d8ed54c961a052bfd01a64cd79b11928a9d5b75146a0828888"), "Block size bytes for keccak224") XCTAssertEqual(Array(repeating: 0x00, count: 136).sha3(.keccak256), Array(hex: "3a5912a7c5faa06ee4fe906253e339467a9ce87d533c65be3c15cb231cdb25f9"), "Block size bytes for keccak256") XCTAssertEqual(Array(repeating: 0x00, count: 104).sha3(.keccak384), Array(hex: "768e10c2eb9903fba6bf290669bf98bd03ce42e7492da9abb88cbbe2212ed153c857e4e883fb1b03a498391935ec6112"), "Block size bytes for keccak384") XCTAssertEqual(Array(repeating: 0x00, count: 72).sha3(.keccak512), Array(hex: "bcf38e5b375422155b4d8eb150682a14778b0695d709cec479d013a772497bc8d7050ef2a23d69609d609b15e5001f275c4619270ffbd6e8c06a7a5bf72334b3"), "Block size bytes for keccak512") // keccak two times block size bytes XCTAssertEqual(Array(repeating: 0x00, count: 288).sha3(.keccak224), Array(hex: "846f930bf21e7ec2175a635379adbdbce9ed9de6a34396c4a11aaf3c"), "Two times block size bytes for keccak224") XCTAssertEqual(Array(repeating: 0x00, count: 272).sha3(.keccak256), Array(hex: "a8005c7a3125b6c3629b4181eca54d18721e41fef639718d205beb00b366ed7d"), "Two times block size bytes for keccak256") XCTAssertEqual(Array(repeating: 0x00, count: 208).sha3(.keccak384), Array(hex: "db6451e6fb59ca16c9ba896de2967b07ca331e9558e21257cb6b26f126ed480c841d37788907f77ef71f8258218b0203"), "Two times block size bytes for keccak384") XCTAssertEqual(Array(repeating: 0x00, count: 144).sha3(.keccak512), Array(hex: "04ddaacd88ce54a4acb468b792d5177ace573e9871dc10b33d02be637b674373601ba5f433b67cc6ba8dc3a1707052f1f6bffc55ef1580aca021ead8bc8e1f22"), "Two times block size bytes for keccak512") // nist sha3 block size bytes XCTAssertEqual(Array(repeating: 0x00, count: 144).sha3(.sha224), Array(hex: "f2b8486fceee2c6a11a604ce4efe217da854829c2c2dcc9a23758b4d"), "Block size bytes for sha3 sha224") XCTAssertEqual(Array(repeating: 0x00, count: 136).sha3(.sha256), Array(hex: "e772c9cf9eb9c991cdfcf125001b454fdbc0a95f188d1b4c844aa032ad6e075e"), "Block size bytes for sha3 sha256") XCTAssertEqual(Array(repeating: 0x00, count: 104).sha3(.sha384), Array(hex: "aaed6beb61b1f9a9b469d38a27a35edde7f676f4603e67f5424c7588043b869ebbfcfc3ecee2ae6f5ecfaf7f706c49e3"), "Block size bytes for sha3 sha384") XCTAssertEqual(Array(repeating: 0x00, count: 72).sha3(.sha512), Array(hex: "f8d76fdd8a082a67eaab47b5518ac486cb9a90dcb9f3c9efcfd86d5c8b3f1831601d3c8435f84b9e56da91283d5b98040e6e7b2c8dd9aa5bd4ebdf1823a7cf29"), "Block size bytes for sha3 sha512") // nist sha3 two times block size bytes XCTAssertEqual(Array(repeating: 0x00, count: 288).sha3(.sha224), Array(hex: "920370d3fec17c0ecbc2b5b7cd64f551860fb93384e0dc4fcaf2e1ba"), "Two times block size bytes for sha3 sha224") XCTAssertEqual(Array(repeating: 0x00, count: 272).sha3(.sha256), Array(hex: "5d86a8cc4aa8f0d98146a747281865a625a19f9580eef32e38905920bc532c5c"), "Two times block size bytes for sha3 sha256") XCTAssertEqual(Array(repeating: 0x00, count: 208).sha3(.sha384), Array(hex: "e741867850b8753bf7fa714b11c1ca9904d0494adaf5e2db43cca42f39637bd67685279d9dfcc45d56e8c288273904af"), "Two times block size bytes for sha3 sha384") XCTAssertEqual(Array(repeating: 0x00, count: 144).sha3(.sha512), Array(hex: "07625da1770011d59b0a71a8dec551f0ddf1917e4117fc860bd7e0a0e42f3e012284f86d509e2f22a8682aea5930197fc1f3c353d0141665c9ac2643278c3821"), "Two times block size bytes for sha3 sha512") // *** End Multiple of block size *** } func testMD5Data() { let data = [0x31, 0x32, 0x33] as Array // "1", "2", "3" XCTAssertEqual(Digest.md5(data), [0x20, 0x2C, 0xB9, 0x62, 0xAC, 0x59, 0x07, 0x5B, 0x96, 0x4B, 0x07, 0x15, 0x2D, 0x23, 0x4B, 0x70], "MD5 calculation failed") } func testMD5Updates() { do { var hash = MD5() _ = try hash.update(withBytes: [0x31, 0x32]) _ = try hash.update(withBytes: [0x33]) let result = try hash.finish() XCTAssertEqual(result, [0x20, 0x2C, 0xB9, 0x62, 0xAC, 0x59, 0x07, 0x5B, 0x96, 0x4B, 0x07, 0x15, 0x2D, 0x23, 0x4B, 0x70]) } catch { XCTFail() } } func testSHA1Updatable1() { do { var hash = SHA1() _ = try hash.update(withBytes: [0x31, 0x32]) _ = try hash.update(withBytes: [0x33]) XCTAssertEqual(try hash.finish().toHexString(), "40bd001563085fc35165329ea1ff5c5ecbdbbeef", "Failed") } catch { XCTFail() } } func testSHA1Updatable2() { do { var hash = SHA1() _ = try hash.update(withBytes: [0x31, 0x32]) _ = try hash.update(withBytes: [0x33]) _ = try hash.update(withBytes: Array(repeating: 0x33, count: 64)) XCTAssertEqual(try hash.finish().toHexString(), "0e659367eff83a6b868a35b96ac305b270025e86", "Failed") } catch { XCTFail() } } func testCRC32() { let data: Data = Data(bytes: [49, 50, 51] as Array, count: 3) XCTAssertEqual(data.crc32(seed: nil).toHexString(), "884863d2", "CRC32 calculation failed") XCTAssertEqual("".crc32(seed: nil), "00000000", "CRC32 calculation failed") } func testCRC32C() { let data: Data = Data(bytes: [0x32, 0, 0, 0] as Array, count: 4) XCTAssertEqual(data.crc32c(seed: nil).toHexString(), "c941cdf0", "CRC32C calculation failed") XCTAssertEqual("".crc32c(seed: nil), "00000000", "CRC32 calculation failed") } func testCRC32NotReflected() { let bytes: Array = [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39] let data: Data = Data(bytes: bytes, count: bytes.count) XCTAssertEqual(data.crc32(seed: nil, reflect: false).toHexString(), "fc891918", "CRC32 (with reflection) calculation failed") XCTAssertEqual("".crc32(seed: nil, reflect: false), "00000000", "CRC32 (with reflection) calculation failed") } func testCRC16() { let result = Checksum.crc16([49, 50, 51, 52, 53, 54, 55, 56, 57] as Array) XCTAssert(result == 0xBB3D, "CRC16 failed") } func testChecksum() { let data: Data = Data(bytes: [49, 50, 51] as Array, count: 3) XCTAssert(data.checksum() == 0x96, "Invalid checksum") } func testChecksumPerformance() { let len = 1_000_000 let a = [UInt8](unsafeUninitializedCapacity: len) { buf, count in for i in 0.. [(String, (DigestTests) -> () -> Void)] { let tests = [ ("testMD5", testMD5), ("testSHA1", testSHA1), ("testSHA2", testSHA2), ("testSHA3", testSHA3), ("testMD5Data", testMD5Data), ("testMD5Updates", testMD5Updates), ("testSHA1Updatable1", testSHA1Updatable1), ("testSHA1Updatable2", testSHA1Updatable2), ("testCRC32", testCRC32), ("testCRC32NotReflected", testCRC32NotReflected), ("testCRC16", testCRC16), ("testChecksum", testChecksum), ("testSHAPartialUpdates", testSHAPartialUpdates) ] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/DigestTestsPerf.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // // http://www.di-mgt.com.au/sha_testvectors.html (http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf) // import Foundation import XCTest @testable import CryptoSwift final class DigestTestsPerf: XCTestCase { func testMD5Performance() { measureMetrics([XCTPerformanceMetric.wallClockTime], automaticallyStartMeasuring: false) { let arr = Array(repeating: 200, count: 1024 * 1024) self.startMeasuring() _ = Digest.md5(arr) self.stopMeasuring() } } func testSHA1Performance() { measureMetrics([XCTPerformanceMetric.wallClockTime], automaticallyStartMeasuring: false) { let arr = Array(repeating: 200, count: 1024 * 1024) self.startMeasuring() _ = Digest.sha1(arr) self.stopMeasuring() } } // Keep it to compare /* func testSHA1PerformanceCC() { measureMetrics([XCTPerformanceMetric.wallClockTime], automaticallyStartMeasuring: false) { let arr = Array(repeating: 200, count: 1024 * 1024) self.startMeasuring() var digest = Array(repeating: 0, count: Int(CC_SHA1_DIGEST_LENGTH)) CC_SHA1(arr, CC_LONG(arr.count), &digest) self.stopMeasuring() } } */ } extension DigestTestsPerf { static func allTests() -> [(String, (DigestTestsPerf) -> () -> Void)] { [ ("testMD5Performance", testMD5Performance), ("testSHA1Performance", testSHA1Performance) ] } } ================================================ FILE: Tests/CryptoSwiftTests/Error+Extension.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation #if !_runtime(_ObjC) extension Error { var localizedDescription: String { "\(self)" } } #endif ================================================ FILE: Tests/CryptoSwiftTests/ExtensionsTest.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation import XCTest @testable import CryptoSwift final class ExtensionsTest: XCTestCase { func testBytes() { let size = MemoryLayout.size // 32 or 64 bit let i: UInt32 = 1024 var bytes = i.bytes() XCTAssertTrue(bytes.count == size, "Invalid bytes length = \(bytes.count)") // test padding bytes = i.bytes(totalBytes: 16) XCTAssertTrue(bytes.count == 16, "Invalid return type \(bytes.count)") XCTAssertTrue(bytes[14] == 4, "Invalid return type \(bytes.count)") } func testToUInt32Array() { let chunk: ArraySlice = [0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1] let result = chunk.toUInt32Array() XCTAssert(result.count == 2, "Invalid conversion") XCTAssertEqual(result[0], 0x5060708) XCTAssertEqual(result[1], 0x1020304) } func testToUInt32Performance() { let len = 1_000_000 let a = [UInt8](unsafeUninitializedCapacity: len) { buf, count in for i in 0..(hex: "0xb1b1b2b2") XCTAssertEqual(bytes, [177, 177, 178, 178]) let str = "b1b2b3b3b3b3b3b3b1b2b3b3b3b3b3b3" let array = Array(hex: str) let hex = array.toHexString() XCTAssertEqual(str, hex) } func testToHexStringPerformance() { let len = 100000 let a = [UInt8](unsafeUninitializedCapacity: len) { buf, count in for i in 0.. [(String, (ExtensionsTest) -> () -> Void)] { let tests = [ ("testBytes", testBytes), ("testToUInt32Array", testToUInt32Array), ("testDataInit", testDataInit), ("testStringEncrypt", testStringEncrypt), ("testStringDecryptBase64", testStringDecryptBase64), ("testEmptyStringEncrypt", testEmptyStringEncrypt), ("testArrayInitHex", testArrayInitHex) ] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/ExtensionsTestPerf.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation import XCTest @testable import CryptoSwift final class ExtensionsTestPerf: XCTestCase { func testArrayInitHexPerformance() { var str = "b1b2b3b3b3b3b3b3b1b2b3b3b3b3b3b3" for _ in 0...12 { str += str } measure { _ = Array(hex: str) } } } extension ExtensionsTestPerf { static func allTests() -> [(String, (ExtensionsTestPerf) -> () -> Void)] { let tests = [ ("testArrayInitHexPerformance", testArrayInitHexPerformance) ] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/HKDFTests.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import XCTest @testable import CryptoSwift class HKDFTests: XCTestCase { /// All test cases are implemented with regard to RFC 5869 /// https://www.ietf.org/rfc/rfc5869.txt func testHKDF1() { let password = Array(hex: "0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") let salt = Array(hex: "0x000102030405060708090a0b0c") let info = Array(hex: "0xf0f1f2f3f4f5f6f7f8f9") let keyLength = 42 let variant = HMAC.Variant.sha2(.sha256) let reference = Array(hex: "0x3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865") XCTAssertEqual(reference, try HKDF(password: password, salt: salt, info: info, keyLength: keyLength, variant: variant).calculate()) } func testHKDF2() { let password = Array(hex: "0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f") let salt = Array(hex: "0x606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf") let info = Array(hex: "0xb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff") let keyLength = 82 let variant = HMAC.Variant.sha2(.sha256) let reference = Array(hex: "0xb11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87") XCTAssertEqual(reference, try HKDF(password: password, salt: salt, info: info, keyLength: keyLength, variant: variant).calculate()) } func testHKDF3() { let password = Array(hex: "0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") let keyLength = 42 let variant = HMAC.Variant.sha2(.sha256) let reference = Array(hex: "0x8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8") XCTAssertEqual(reference, try HKDF(password: password, keyLength: keyLength, variant: variant).calculate()) } func testHKDF4() { let password = Array(hex: "0x0b0b0b0b0b0b0b0b0b0b0b") let salt = Array(hex: "0x000102030405060708090a0b0c") let info = Array(hex: "0xf0f1f2f3f4f5f6f7f8f9") let keyLength = 42 let variant = HMAC.Variant.sha1 let reference = Array(hex: "0x085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896") XCTAssertEqual(reference, try HKDF(password: password, salt: salt, info: info, keyLength: keyLength, variant: variant).calculate()) } func testHKDF5() { let password = Array(hex: "0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f") let salt = Array(hex: "0x606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf") let info = Array(hex: "0xb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff") let keyLength = 82 let variant = HMAC.Variant.sha1 let reference = Array(hex: "0x0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4") XCTAssertEqual(reference, try HKDF(password: password, salt: salt, info: info, keyLength: keyLength, variant: variant).calculate()) } func testHKDF6() { let password = Array(hex: "0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") let keyLength = 42 let variant = HMAC.Variant.sha1 let reference = Array(hex: "0x0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918") XCTAssertEqual(reference, try HKDF(password: password, keyLength: keyLength, variant: variant).calculate()) } static func allTests() -> [(String, (HKDFTests) -> () -> Void)] { let tests = [ ("Basic test case with SHA-256", testHKDF1), ("Test with SHA-256 and longer inputs/outputs", testHKDF2), ("Test with SHA-256 and zero-length salt/info", testHKDF3), ("Basic test case with SHA-1", testHKDF4), ("Test with SHA-1 and longer inputs/outputs", testHKDF5), ("Test with SHA-1 and zero-length salt/info", testHKDF6) ] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/HMACTests.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import XCTest @testable import CryptoSwift final class HMACTests: XCTestCase { func testMD5() { let key: Array = [] let msg: Array = [] let expectedMac: Array = [0x74, 0xe6, 0xf7, 0x29, 0x8a, 0x9c, 0x2d, 0x16, 0x89, 0x35, 0xf5, 0x8c, 0x00, 0x1b, 0xad, 0x88] let hmac = try! HMAC(key: key, variant: .md5).authenticate(msg) XCTAssertEqual(hmac, expectedMac, "Invalid authentication result") } func testSHA1() { XCTAssertEqual(try HMAC(key: [], variant: .sha1).authenticate([]), Array(hex: "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d")) // echo -n "test" | openssl sha1 -hmac 'test' XCTAssertEqual(try HMAC(key: Array(hex: "74657374"), variant: .sha1).authenticate(Array(hex: "74657374")), Array(hex: "0c94515c15e5095b8a87a50ba0df3bf38ed05fe6")) // echo -n "test" | openssl sha1 -hmac '0123456789012345678901234567890123456789012345678901234567890123' XCTAssertEqual(try HMAC(key: Array(hex: "30313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233"), variant: .sha1).authenticate(Array(hex: "74657374")), Array(hex: "23cea58b0c484ed005434938ee70a938d7524e91")) } func testSHA256() { let key: Array = [] let msg: Array = [] let expectedMac: Array = [0xb6, 0x13, 0x67, 0x9a, 0x08, 0x14, 0xd9, 0xec, 0x77, 0x2f, 0x95, 0xd7, 0x78, 0xc3, 0x5f, 0xc5, 0xff, 0x16, 0x97, 0xc4, 0x93, 0x71, 0x56, 0x53, 0xc6, 0xc7, 0x12, 0x14, 0x42, 0x92, 0xc5, 0xad] let hmac = try! HMAC(key: key, variant: .sha2(.sha256)).authenticate(msg) XCTAssertEqual(hmac, expectedMac, "Invalid authentication result") } func testSHA384() { let key: Array = [] let msg: Array = [] let expectedMac: Array = [0x6c, 0x1f, 0x2e, 0xe9, 0x38, 0xfa, 0xd2, 0xe2, 0x4b, 0xd9, 0x12, 0x98, 0x47, 0x43, 0x82, 0xca, 0x21, 0x8c, 0x75, 0xdb, 0x3d, 0x83, 0xe1, 0x14, 0xb3, 0xd4, 0x36, 0x77, 0x76, 0xd1, 0x4d, 0x35, 0x51, 0x28, 0x9e, 0x75, 0xe8, 0x20, 0x9c, 0xd4, 0xb7, 0x92, 0x30, 0x28, 0x40, 0x23, 0x4a, 0xdc] let hmac = try! HMAC(key: key, variant: .sha2(.sha384)).authenticate(msg) XCTAssertEqual(hmac, expectedMac, "Invalid authentication result") } func testSHA512() { let key: Array = [] let msg: Array = [] let expectedMac: Array = [0xb9, 0x36, 0xce, 0xe8, 0x6c, 0x9f, 0x87, 0xaa, 0x5d, 0x3c, 0x6f, 0x2e, 0x84, 0xcb, 0x5a, 0x42, 0x39, 0xa5, 0xfe, 0x50, 0x48, 0x0a, 0x6e, 0xc6, 0x6b, 0x70, 0xab, 0x5b, 0x1f, 0x4a, 0xc6, 0x73, 0x0c, 0x6c, 0x51, 0x54, 0x21, 0xb3, 0x27, 0xec, 0x1d, 0x69, 0x40, 0x2e, 0x53, 0xdf, 0xb4, 0x9a, 0xd7, 0x38, 0x1e, 0xb0, 0x67, 0xb3, 0x38, 0xfd, 0x7b, 0x0c, 0xb2, 0x22, 0x47, 0x22, 0x5d, 0x47] let hmac = try! HMAC(key: key, variant: .sha2(.sha512)).authenticate(msg) XCTAssertEqual(hmac, expectedMac, "Invalid authentication result") } static let allTests = [ ("testMD5", testMD5), ("testSHA1", testSHA1), ("testSHA256", testSHA256), ("testSHA384", testSHA384), ("testSHA512", testSHA512) ] } ================================================ FILE: Tests/CryptoSwiftTests/PBKDF.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import XCTest @testable import CryptoSwift class PBKDF: XCTestCase { func testPBKDF1() { let password: Array = [0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64] let salt: Array = [0x78, 0x57, 0x8e, 0x5a, 0x5d, 0x63, 0xcb, 0x06] let value = try! PKCS5.PBKDF1(password: password, salt: salt, iterations: 1000, keyLength: 16).calculate() XCTAssertEqual(value.toHexString(), "dc19847e05c64d2faf10ebfb4a3d2a20") } func testPBKDF2() { // P = "password", S = "salt", c = 1, dkLen = 20 XCTAssertEqual([0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71, 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06, 0x2f, 0xe0, 0x37, 0xa6], try PKCS5.PBKDF2(password: [0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64], salt: [0x73, 0x61, 0x6c, 0x74], iterations: 1, keyLength: 20, variant: .sha1).calculate()) // P = "password", S = "salt", c = 2, dkLen = 20 XCTAssertEqual([0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c, 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0, 0xd8, 0xde, 0x89, 0x57], try PKCS5.PBKDF2(password: [0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64], salt: [0x73, 0x61, 0x6c, 0x74], iterations: 2, keyLength: 20, variant: .sha1).calculate()) // P = "password", S = "salt", c = 4096, dkLen = 20 XCTAssertEqual([0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a, 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0, 0x65, 0xa4, 0x29, 0xc1], try PKCS5.PBKDF2(password: [0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64], salt: [0x73, 0x61, 0x6c, 0x74], iterations: 4096, keyLength: 20, variant: .sha1).calculate()) // P = "password", S = "salt", c = 16777216, dkLen = 20 // Commented because it takes a lot of time with Debug build to finish. // XCTAssertEqual([0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4, 0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c, 0x26, 0x34, 0xe9, 0x84], // try PKCS5.PBKDF2(password: [0x70, 0x61, 0x73, 0x73, 0x77, 0x6F, 0x72, 0x64], salt: [0x73, 0x61, 0x6C, 0x74], iterations: 16777216, keyLength: 20, variant: .sha1).calculate()) // P = "passwordPASSWORDpassword", S = "saltSALTsaltSALTsaltSALTsaltSALTsalt", c = 4096, dkLen = 25 XCTAssertEqual([0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b, 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a, 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, 0x38], try PKCS5.PBKDF2(password: [0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64], salt: [0x73, 0x61, 0x6c, 0x74, 0x53, 0x41, 0x4c, 0x54, 0x73, 0x61, 0x6c, 0x74, 0x53, 0x41, 0x4c, 0x54, 0x73, 0x61, 0x6c, 0x74, 0x53, 0x41, 0x4c, 0x54, 0x73, 0x61, 0x6c, 0x74, 0x53, 0x41, 0x4c, 0x54, 0x73, 0x61, 0x6c, 0x74], iterations: 4096, keyLength: 25, variant: .sha1).calculate()) // P = "pass\0word", S = "sa\0lt", c = 4096, dkLen = 16 XCTAssertEqual([0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d, 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3], try PKCS5.PBKDF2(password: [0x70, 0x61, 0x73, 0x73, 0x00, 0x77, 0x6f, 0x72, 0x64], salt: [0x73, 0x61, 0x00, 0x6c, 0x74], iterations: 4096, keyLength: 16, variant: .sha1).calculate()) // P = "", S = "salt", c = 1, dkLen = 20 XCTAssertEqual([0xa3, 0x3d, 0xdd, 0xc3, 0x04, 0x78, 0x18, 0x55, 0x15, 0x31, 0x1f, 0x87, 0x52, 0x89, 0x5d, 0x36, 0xea, 0x43, 0x63, 0xa2], try PKCS5.PBKDF2(password: [], salt: [0x73, 0x61, 0x6c, 0x74], iterations: 1, keyLength: 20, variant: .sha1).calculate()) } func testPBKDF2Length() { let password: Array = "s33krit".bytes let salt: Array = "nacl".bytes let value = try! PKCS5.PBKDF2(password: password, salt: salt, iterations: 2, keyLength: 8, variant: .sha1).calculate() XCTAssertEqual(value.toHexString(), "a53cf3df485e5cd9") } static func allTests() -> [(String, (PBKDF) -> () -> Void)] { let tests = [ ("testPBKDF1", testPBKDF1), ("testPBKDF2", testPBKDF2), ("testPBKDF2Length", testPBKDF2Length) ] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/PBKDFPerf.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import XCTest @testable import CryptoSwift class PBKDFPerf: XCTestCase { func testPerformance() { let password: Array = "s33krit".bytes let salt: Array = "nacl".bytes measure { _ = try! PKCS5.PBKDF2(password: password, salt: salt, iterations: 65536, keyLength: 32, variant: .sha1).calculate() } } static func allTests() -> [(String, (PBKDFPerf) -> () -> Void)] { let tests = [("testPerformance", testPerformance)] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/PaddingTests.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import XCTest @testable import CryptoSwift final class PaddingTests: XCTestCase { func testPKCS7_0() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6] let expected: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16] let padded = PKCS7.Padding().add(to: input, blockSize: 16) XCTAssertEqual(padded, expected, "PKCS7 failed") let clean = PKCS7.Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "PKCS7 failed") } func testPKCS7_1() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5] let expected: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 1] let padded = PKCS7.Padding().add(to: input, blockSize: 16) XCTAssertEqual(padded, expected, "PKCS7 failed") let clean = PKCS7.Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "PKCS7 failed") } func testPKCS7_2() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4] let expected: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 2, 2] let padded = PKCS7.Padding().add(to: input, blockSize: 16) XCTAssertEqual(padded, expected, "PKCS7 failed") let clean = PKCS7.Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "PKCS7 failed") } func testZeroPadding1() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9] let expected: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0] let padding = ZeroPadding() XCTAssertEqual(padding.add(to: input, blockSize: 16), expected, "ZeroPadding failed") XCTAssertEqual(padding.remove(from: padding.add(to: input, blockSize: 16), blockSize: 16), input, "ZeroPadding failed") } func testZeroPadding2() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6] let expected: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] let padding = ZeroPadding() XCTAssertEqual(padding.add(to: input, blockSize: 16), expected, "ZeroPadding failed") XCTAssertEqual(padding.remove(from: padding.add(to: input, blockSize: 16), blockSize: 16), input, "ZeroPadding failed") } func testISO78164_0() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 0x80] let expected: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 0x80, 0x80] let padded = ISO78164Padding().add(to: input, blockSize: 16) XCTAssertEqual(padded, expected, "ISO78164 failed") let clean = ISO78164Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "ISO78164 failed") } func testISO78164_1() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 0] let expected: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 0, 0x80] + [UInt8](repeating: UInt8(0), count: 15) let padded = ISO78164Padding().add(to: input, blockSize: 16) XCTAssertEqual(padded, expected, "ISO78164 failed") let clean = ISO78164Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "ISO78164 failed") } func testISO78164_2() { let input: Array = [] let expected: Array = [0x80] + [UInt8](repeating: UInt8(0), count: 15) let padded = ISO78164Padding().add(to: input, blockSize: 16) XCTAssertEqual(padded, expected, "ISO78164 failed") let clean = ISO78164Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "ISO78164 failed") } func testISO10126_0() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3] let padded = ISO10126Padding().add(to: input, blockSize: 16) XCTAssertTrue(padded.starts(with: input), "ISO10126 failed") XCTAssertEqual(padded.last, 3, "ISO10126 failed") XCTAssertEqual(padded.count, 16) let clean = ISO10126Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "ISO10126 failed") } func testISO10126_1() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6] let padded = ISO10126Padding().add(to: input, blockSize: 16) XCTAssertTrue(padded.starts(with: input), "ISO10126 failed") XCTAssertEqual(padded.last, 16, "ISO10126 failed") XCTAssertEqual(padded.count, 32) let clean = ISO10126Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "ISO10126 failed") } func testISO10126_2() { let input: Array = [] let padded = ISO10126Padding().add(to: input, blockSize: 16) XCTAssertTrue(padded.starts(with: input), "ISO10126 failed") XCTAssertEqual(padded.last, 16, "ISO10126 failed") XCTAssertEqual(padded.count, 16) let clean = ISO10126Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "ISO10126 failed") } func testEMSAPKCS1v15_1() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6] let padded = EMSAPKCS1v15Padding().add(to: input, blockSize: 32) XCTAssertEqual(padded.prefix(2), [0, 1], "EMSAPKCS1v15 failed") XCTAssertTrue(padded.suffix(16) == input, "EMSAPKCS1v15 failed") XCTAssertEqual(padded.count, 32) let clean = EMSAPKCS1v15Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "EMSAPKCS1v15 failed") } func testEMSAPKCS1v15_2() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6] let padded = EMSAPKCS1v15Padding().add(to: input, blockSize: 16) XCTAssertEqual(padded.prefix(2), [0, 1], "EMSAPKCS1v15 failed") XCTAssertTrue(padded.suffix(16) == input, "EMSAPKCS1v15 failed") XCTAssertEqual(padded.count, 32) let clean = EMSAPKCS1v15Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "EMSAPKCS1v15 failed") } func testEMSAPKCS1v15_3() { let input: Array = [] let padded = EMSAPKCS1v15Padding().add(to: input, blockSize: 16) XCTAssertTrue(padded.starts(with: input), "EMSAPKCS1v15 failed") XCTAssertEqual(padded.last, 0, "EMSAPKCS1v15 failed") XCTAssertEqual(padded.count, 16) let clean = EMSAPKCS1v15Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "EMSAPKCS1v15 failed") } func testEMSAPKCS1v15_4() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3] let padded = EMSAPKCS1v15Padding().add(to: input, blockSize: 16) XCTAssertEqual(padded.prefix(2), [0, 1], "EMSAPKCS1v15 failed") XCTAssertTrue(padded.suffix(13) == input, "EMSAPKCS1v15 failed") XCTAssertEqual(padded.count, 32) let clean = EMSAPKCS1v15Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "EMSAPKCS1v15 failed") } func testEMSAPKCS1v15_5() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2] let padded = EMSAPKCS1v15Padding().add(to: input, blockSize: 16) XCTAssertEqual(padded.prefix(2), [0, 1], "EMSAPKCS1v15 failed") XCTAssertTrue(padded.suffix(12) == input, "EMSAPKCS1v15 failed") XCTAssertEqual(padded.count, 16) let clean = EMSAPKCS1v15Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "EMSAPKCS1v15 failed") } func testEMEPKCS1v15_1() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6] let padded = EMEPKCS1v15Padding().add(to: input, blockSize: 32) XCTAssertEqual(padded.prefix(2), [0, 2], "EMEPKCS1v15 failed") XCTAssertTrue(padded.suffix(16) == input, "EMEPKCS1v15 failed") XCTAssertEqual(padded.count, 32) let clean = EMEPKCS1v15Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "EMEPKCS1v15 failed") } func testEMEPKCS1v15_2() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6] let padded = EMEPKCS1v15Padding().add(to: input, blockSize: 16) XCTAssertEqual(padded.prefix(2), [0, 2], "EMEPKCS1v15 failed") XCTAssertTrue(padded.suffix(16) == input, "EMEPKCS1v15 failed") XCTAssertEqual(padded.count, 32) let clean = EMEPKCS1v15Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "EMEPKCS1v15 failed") } func testEMEPKCS1v15_3() { let input: Array = [] let padded = EMEPKCS1v15Padding().add(to: input, blockSize: 16) XCTAssertTrue(padded.starts(with: input), "EMEPKCS1v15 failed") XCTAssertEqual(padded.last, 0, "EMEPKCS1v15 failed") XCTAssertEqual(padded.count, 16) let clean = EMEPKCS1v15Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "EMEPKCS1v15 failed") } func testEMEPKCS1v15_4() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3] let padded = EMEPKCS1v15Padding().add(to: input, blockSize: 16) XCTAssertEqual(padded.prefix(2), [0, 2], "EMEPKCS1v15 failed") XCTAssertTrue(padded.suffix(13) == input, "EMEPKCS1v15 failed") XCTAssertEqual(padded.count, 32) let clean = EMEPKCS1v15Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "EMEPKCS1v15 failed") } func testEMEPKCS1v15_5() { let input: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2] let padded = EMEPKCS1v15Padding().add(to: input, blockSize: 16) XCTAssertEqual(padded.prefix(2), [0, 2], "EMEPKCS1v15 failed") XCTAssertTrue(padded.suffix(12) == input, "EMEPKCS1v15 failed") XCTAssertEqual(padded.count, 16) let clean = EMEPKCS1v15Padding().remove(from: padded, blockSize: nil) XCTAssertEqual(clean, input, "EMEPKCS1v15 failed") } static let allTests = [ ("testPKCS7_0", testPKCS7_0), ("testPKCS7_1", testPKCS7_1), ("testPKCS7_2", testPKCS7_2), ("testZeroPadding1", testZeroPadding1), ("testZeroPadding2", testZeroPadding2), ("testISO78164_0", testISO78164_0), ("testISO78164_1", testISO78164_1), ("testISO78164_2", testISO78164_2), ("testISO10126_0", testISO10126_0), ("testISO10126_1", testISO10126_1), ("testISO10126_2", testISO10126_2), ("testEMSAPKCS1v15_1", testEMSAPKCS1v15_1), ("testEMSAPKCS1v15_2", testEMSAPKCS1v15_2), ("testEMSAPKCS1v15_3", testEMSAPKCS1v15_3), ("testEMSAPKCS1v15_4", testEMSAPKCS1v15_4), ("testEMSAPKCS1v15_5", testEMSAPKCS1v15_5), ("testEMEPKCS1v15_1", testEMEPKCS1v15_1), ("testEMEPKCS1v15_2", testEMEPKCS1v15_2), ("testEMEPKCS1v15_3", testEMEPKCS1v15_3), ("testEMEPKCS1v15_4", testEMEPKCS1v15_4), ("testEMEPKCS1v15_5", testEMEPKCS1v15_5), ] } ================================================ FILE: Tests/CryptoSwiftTests/Poly1305Tests.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation import XCTest @testable import CryptoSwift final class Poly1305Tests: XCTestCase { func testPoly1305() { let key: Array = [0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc] let msg: Array = [0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1] let expectedMac: Array = [0xdd, 0xb9, 0xda, 0x7d, 0xdd, 0x5e, 0x52, 0x79, 0x27, 0x30, 0xed, 0x5c, 0xda, 0x5f, 0x90, 0xa4] XCTAssertEqual(try Poly1305(key: key).authenticate(msg), expectedMac) // extensions let msgData = Data( msg) XCTAssertEqual(try msgData.authenticate(with: Poly1305(key: key)), Data( expectedMac), "Invalid authentication result") } // https://github.com/krzyzanowskim/CryptoSwift/issues/183 func testIssue183() { let key: Array = [111, 53, 197, 181, 1, 92, 67, 199, 37, 92, 76, 167, 12, 35, 75, 226, 198, 34, 107, 84, 79, 6, 231, 10, 25, 221, 14, 155, 81, 244, 15, 203] let message: Array = [208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 210, 40, 78, 3, 161, 87, 187, 96, 253, 104, 187, 87, 87, 249, 56, 5, 156, 122, 121, 196, 192, 254, 58, 98, 22, 47, 151, 205, 201, 108, 143, 197, 99, 182, 109, 59, 63, 172, 111, 120, 185, 175, 129, 59, 126, 68, 140, 237, 126, 175, 49, 224, 249, 245, 37, 75, 252, 69, 215, 171, 27, 163, 16, 185, 239, 184, 144, 37, 131, 242, 12, 90, 134, 24, 237, 209, 127, 71, 86, 122, 173, 238, 73, 186, 58, 102, 112, 90, 217, 243, 251, 110, 85, 106, 18, 172, 167, 179, 173, 73, 125, 9, 129, 132, 80, 70, 4, 254, 178, 211, 200, 207, 231, 232, 17, 176, 127, 153, 120, 71, 164, 139, 56, 106, 71, 96, 79, 11, 213, 243, 66, 53, 167, 108, 233, 250, 136, 69, 190, 191, 12, 136, 24, 157, 202, 49, 158, 152, 150, 34, 88, 132, 112, 74, 168, 153, 116, 31, 7, 61, 60, 22, 199, 108, 187, 209, 114, 234, 185, 247, 41, 68, 184, 95, 169, 60, 126, 73, 59, 54, 126, 162, 90, 18, 32, 230, 123, 2, 40, 74, 177, 127, 219, 93, 186, 22, 75, 251, 101, 95, 160, 68, 235, 77, 2, 10, 202, 2, 0, 0, 0, 0, 0, 0, 0, 208, 0, 0, 0, 0, 0, 0, 0] let expectedMac: Array = [68, 216, 92, 163, 164, 144, 55, 43, 185, 18, 83, 92, 41, 133, 72, 168] XCTAssertEqual(try message.authenticate(with: Poly1305(key: key)), expectedMac) } static let allTests = [ ("testPoly1305", testPoly1305), ("testIssue183", testIssue183) ] } ================================================ FILE: Tests/CryptoSwiftTests/RSASecKeyTests.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2021 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // #if canImport(Security) import Security import XCTest @testable import CryptoSwift final class RSASecKeyTests: XCTestCase { // MARK: SecKey <-> RSA Interoperability /// From CryptoSwift RSA -> External Representation -> SecKey /// /// This test enforces that /// 1) We can export the raw external representation of a CryptoSwift RSA Public Key /// 2) And that we can import / create an RSA SecKey from that raw external representation /// 3) Proves interoperability between Apple's `Security` Framework and `CryptoSwift` func testRSAExternalRepresentationPublic() throws { // Generate a CryptoSwift RSA Key let rsaCryptoSwift = try RSA(keySize: 1024) // Get the key's rawExternalRepresentation let rsaCryptoSwiftRawRep = try rsaCryptoSwift.publicKeyDER() // We should be able to instantiate an RSA SecKey from this data let attributes: [String: Any] = [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeyClass as String: kSecAttrKeyClassPublic, kSecAttrKeySizeInBits as String: 1024, kSecAttrIsPermanent as String: false ] var error: Unmanaged? guard let rsaSecKey = SecKeyCreateWithData(Data(rsaCryptoSwiftRawRep) as CFData, attributes as CFDictionary, &error) else { XCTFail("Error constructing SecKey from raw key data: \(error.debugDescription)") return } // Get the SecKey's external representation var externalRepError: Unmanaged? guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else { XCTFail("Failed to copy external representation for RSA SecKey") return } // Ensure both the CryptoSwift Ext Rep and the SecKey Ext Rep match XCTAssertEqual(rsaSecKeyRawRep, Data(rsaCryptoSwiftRawRep)) XCTAssertEqual(rsaSecKeyRawRep, try rsaCryptoSwift.publicKeyExternalRepresentation()) } /// From CryptoSwift RSA -> External Representation -> SecKey /// /// This test enforces that /// 1) We can export the raw external representation of a 1 byte CryptoSwift RSA Public Key /// 2) And that we can import / create an RSA SecKey from that raw external representation /// 3) Proves interoperability between Apple's `Security` Framework and `CryptoSwift` func testRSAExternalRepresentationPublic_1ByteExponent() throws { // Generate a CryptoSwift RSA Key let n: Array = [ 0xDF, 0x74, 0xEA, 0xA8, 0xB4, 0x77, 0x79, 0xE5, 0x26, 0x0E, 0xD1, 0xD2, 0xF3, 0xDA, 0x85, 0xDE, 0x9E, 0x0C, 0x3F, 0xB5, 0x9F, 0xAA, 0xDD, 0x99, 0x8E, 0x3D, 0xE5, 0x66, 0x32, 0xE3, 0x8C, 0x21, 0x83, 0xBF, 0x0A, 0xFD, 0x70, 0x93, 0x65, 0x34, 0x38, 0xAE, 0x29, 0xBA, 0x0E, 0x0E, 0x05, 0x22, 0x4F, 0x86, 0x5D, 0x3D, 0x66, 0xCE, 0x88, 0xC0, 0x1F, 0x0D, 0xC0, 0xF3, 0x94, 0xEC, 0x40, 0xD3, 0x80, 0xC3, 0x9C, 0x41, 0x46, 0x01, 0xFF, 0xA4, 0x0D, 0x08, 0x8D, 0x49, 0xED, 0x99, 0xB6, 0xA0, 0xBB, 0x6E, 0x72, 0x1C, 0xF3, 0xE2, 0x92, 0x1B, 0xFA, 0x8E, 0x19, 0x02, 0x15, 0x69, 0xAC, 0xB8, 0x51, 0xCA, 0xFA, 0xA2, 0xF0, 0xE4, 0xCA, 0x43, 0xB9, 0x1F, 0x19, 0xFB, 0x39, 0x4E, 0xEC, 0x26, 0x9F, 0x53, 0x3F, 0xD1, 0xF4, 0x24, 0x7F, 0x33, 0x31, 0x00, 0x3A, 0x63, 0x38, 0xA3, 0x60, 0x7F, 0x4B, 0xB2, 0xEA, 0x53, 0x7A, 0xBA, 0xD8, 0xDD, 0x4E, 0xB3, 0xCA, 0x28, 0x55, 0x10, 0x35, 0xD7, 0x3A, 0xFD, 0x3C, 0xBC, 0x11, 0xE4, 0xE7, 0x40, 0x4C, 0x14, 0x96, 0xC4, 0xF6, 0x2C, 0x05, 0xC2, 0x7C, 0x42, 0xB1, 0x4E, 0x7E, 0x51, 0x95, 0x19, 0x63, 0x0F, 0x3B, 0x52, 0xED, 0x27, 0xE0, 0xB3, 0xC5, 0x4B, 0xD0, 0x53, 0xF2, 0xD5, 0x08, 0xBC, 0x07, 0xE7, 0x45, 0x72, 0x04, 0x58, 0x28, 0x5A, 0xDC, 0xA6, 0xC5, 0x5A, 0x67, 0x59, 0x41, 0x99, 0x72, 0xAC, 0x5C, 0x34, 0x6E, 0xE5, 0x04, 0x7F, 0x46, 0x0D, 0xDF, 0xF4, 0x34, 0x6A, 0xE0, 0x64, 0x75, 0xB0, 0xD1, 0xFC, 0x44, 0xB6, 0x3D, 0xB8, 0x0A, 0x4C, 0x97, 0x64, 0x8D, 0xCF, 0xEB, 0x11, 0xE3, 0x34, 0x4F, 0x1B, 0xCE, 0x51, 0xFE, 0xC7, 0xB9, 0x43, 0x4E, 0x86, 0xBB, 0x40, 0x54, 0x43, 0x75, 0x0F, 0x9B, 0xAE, 0xC4, 0x4D, 0x56, 0x4B ] let e: Array = [ 0x03 ] let rsaCryptoSwift = RSA(n: n, e: e) // Get the key's rawExternalRepresentation let rsaCryptoSwiftRawRep = try rsaCryptoSwift.publicKeyDER() // We should be able to instantiate an RSA SecKey from this data let attributes: [String: Any] = [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeyClass as String: kSecAttrKeyClassPublic, kSecAttrKeySizeInBits as String: 2048, kSecAttrIsPermanent as String: false ] var error: Unmanaged? guard let rsaSecKey = SecKeyCreateWithData(Data(rsaCryptoSwiftRawRep) as CFData, attributes as CFDictionary, &error) else { XCTFail("Error constructing SecKey from raw key data: \(error.debugDescription)") return } // Get the SecKey's external representation var externalRepError: Unmanaged? guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else { XCTFail("Failed to copy external representation for RSA SecKey") return } // Ensure both the CryptoSwift Ext Rep and the SecKey Ext Rep match XCTAssertEqual(rsaSecKeyRawRep, Data(rsaCryptoSwiftRawRep)) XCTAssertEqual(rsaSecKeyRawRep, try rsaCryptoSwift.publicKeyExternalRepresentation()) } /// From CryptoSwift RSA -> External Representation -> SecKey /// /// This test enforces that /// 1) We can export the raw external representation of a CryptoSwift RSA Private Key /// 2) And that we can import / create an RSA SecKey from that raw external representation /// 3) Proves interoperability between Apple's `Security` Framework and `CryptoSwift` func testRSAExternalRepresentationPrivate() throws { // Generate a CryptoSwift RSA Key let rsaCryptoSwift = try RSA(keySize: 1024) // Get the key's rawExternalRepresentation let rsaCryptoSwiftRawRep = try rsaCryptoSwift.privateKeyDER() // We should be able to instantiate an RSA SecKey from this data let attributes: [String: Any] = [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits as String: 1024, kSecAttrIsPermanent as String: false ] var error: Unmanaged? guard let rsaSecKey = SecKeyCreateWithData(Data(rsaCryptoSwiftRawRep) as CFData, attributes as CFDictionary, &error) else { XCTFail("Error constructing SecKey from raw key data: \(error.debugDescription)") return } // Get the SecKey's external representation var externalRepError: Unmanaged? guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else { XCTFail("Failed to copy external representation for RSA SecKey") return } // Ensure both the CryptoSwift Ext Rep and the SecKey Ext Rep match XCTAssertEqual(rsaSecKeyRawRep, Data(rsaCryptoSwiftRawRep)) XCTAssertEqual(rsaSecKeyRawRep, try rsaCryptoSwift.externalRepresentation()) } /// From SecKey -> External Representation -> CryptoSwift RSA /// /// This test enforces that /// 1) Given the raw external representation of a Public RSA SecKey, we can import that same key into CryptoSwift /// 2) When we export the raw external representation of the RSA Key we get the exact same data /// 3) Proves interoperability between Apple's `Security` Framework and `CryptoSwift` func testSecKeyExternalRepresentationPublic() throws { // Generate a SecKey RSA Key let parameters: [CFString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeySizeInBits: 1024 ] var error: Unmanaged? // Generate the RSA SecKey guard let rsaSecKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else { XCTFail("Key Generation Error: \(error.debugDescription)") return } // Extract the public key from the private RSA SecKey guard let rsaSecKeyPublic = SecKeyCopyPublicKey(rsaSecKey) else { XCTFail("Public Key Extraction Error") return } // Let's grab the external representation of the public key var externalRepError: Unmanaged? guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKeyPublic, &externalRepError) as? Data else { XCTFail("Failed to copy external representation for RSA SecKey") return } // Ensure we can import the private RSA key into CryptoSwift let rsaCryptoSwift = try RSA(rawRepresentation: rsaSecKeyRawRep) XCTAssertNil(rsaCryptoSwift.d) XCTAssertEqual(rsaSecKeyRawRep, try rsaCryptoSwift.externalRepresentation()) } /// From SecKey -> External Representation -> CryptoSwift RSA /// /// This test enforces that /// 1) Given the raw external representation of a Private RSA SecKey, we can import that same key into CryptoSwift /// 2) When we export the raw external representation of the RSA Key we get the exact same data /// 3) Proves interoperability between Apple's `Security` Framework and `CryptoSwift` func testSecKeyExternalRepresentationPrivate() throws { // Generate a SecKey RSA Key let parameters: [CFString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeySizeInBits: 1024 ] var error: Unmanaged? // Generate the RSA SecKey guard let rsaSecKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else { XCTFail("Key Generation Error: \(error.debugDescription)") return } // Let's grab the external representation var externalRepError: Unmanaged? guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else { XCTFail("Failed to copy external representation for RSA SecKey") return } // Ensure we can import the private RSA key into CryptoSwift let rsaCryptoSwift = try RSA(rawRepresentation: rsaSecKeyRawRep) XCTAssertNotNil(rsaCryptoSwift.d) XCTAssertEqual(rsaSecKeyRawRep, try rsaCryptoSwift.externalRepresentation()) } /// This test generates X RSA keys and tests them between `Security` and `CryptoSwift` for interoperability /// /// For each key generated, this test enforces that /// 1) We can import the raw external representation (generated by the `Security` framework) of the RSA Key into `CryptoSwift` /// 2) When signing messages using a deterministic variant, we get the same output from both `Security` and `CryptoSwift` /// 3) We can verify a signature generated from `CryptoSwift` with `Security` and vice versa /// 4) We can encrypt and decrypt a message generated from `CryptoSwift` with `Security` and vice versa func testRSASecKeys() throws { let tests = 3 let messageToSign: String = "RSA Keys!" for _ in 0..? // Generate the RSA SecKey guard let rsaSecKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else { XCTFail("Key Generation Error: \(error.debugDescription)") break } // Let's grab the external representation var externalRepError: Unmanaged? guard let rsaSecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &externalRepError) as? Data else { XCTFail("Failed to copy external representation for RSA SecKey") break } // Ensure we can import the private RSA key into CryptoSwift let rsaCryptoSwift = try RSA(rawRepresentation: rsaSecKeyRawRep) // Sign the message with both keys and ensure they're the same (the pkcs1v15 signature variant is deterministic) let csSignature = try rsaCryptoSwift.sign(messageToSign.bytes, variant: .message_pkcs1v15_SHA256) let skSignature = try secKeySign(messageToSign.bytes, variant: .rsaSignatureMessagePKCS1v15SHA256, withKey: rsaSecKey) XCTAssertEqual(csSignature, skSignature.byteArray, "Signatures don't match!") // Ensure we can verify each signature using the opposite library XCTAssertTrue(try rsaCryptoSwift.verify(signature: skSignature.byteArray, for: messageToSign.bytes, variant: .message_pkcs1v15_SHA256)) XCTAssertTrue(try self.secKeyVerify(csSignature, forBytes: messageToSign.bytes, usingVariant: .rsaSignatureMessagePKCS1v15SHA256, withKey: rsaSecKey)) // Encrypt with SecKey let skEncryption = try secKeyEncrypt(messageToSign.bytes, usingVariant: .rsaEncryptionRaw, withKey: rsaSecKey) // Decrypt with CryptoSwift Key XCTAssertEqual(try rsaCryptoSwift.decrypt(skEncryption.byteArray, variant: .raw), messageToSign.bytes, "CryptoSwift Decryption of SecKey Encryption Failed") // Encrypt with CryptoSwift let csEncryption = try rsaCryptoSwift.encrypt(messageToSign.bytes, variant: .raw) // Decrypt with SecKey XCTAssertEqual(try self.secKeyDecrypt(csEncryption, usingVariant: .rsaEncryptionRaw, withKey: rsaSecKey).byteArray, messageToSign.bytes, "SecKey Decryption of CryptoSwift Encryption Failed") XCTAssertEqual(csEncryption, skEncryption.byteArray, "Encrypted Data Does Not Match") // Encrypt with SecKey let skEncryption2 = try secKeyEncrypt(messageToSign.bytes, usingVariant: .rsaEncryptionPKCS1, withKey: rsaSecKey) // Decrypt with CryptoSwift Key XCTAssertEqual(try rsaCryptoSwift.decrypt(skEncryption2.byteArray, variant: .pksc1v15), messageToSign.bytes, "CryptoSwift Decryption of SecKey Encryption Failed") // Encrypt with CryptoSwift let csEncryption2 = try rsaCryptoSwift.encrypt(messageToSign.bytes, variant: .pksc1v15) // Decrypt with SecKey XCTAssertEqual(try self.secKeyDecrypt(csEncryption2, usingVariant: .rsaEncryptionPKCS1, withKey: rsaSecKey).byteArray, messageToSign.bytes, "SecKey Decryption of CryptoSwift Encryption Failed") } } private func secKeySign(_ bytes: Array, variant: SecKeyAlgorithm, withKey key: SecKey) throws -> Data { var error: Unmanaged? // Sign the data guard let signature = SecKeyCreateSignature( key, variant, Data(bytes) as CFData, &error ) as Data? else { throw NSError(domain: "Failed to sign bytes: \(bytes)", code: 0) } return signature } private func secKeyVerify(_ signature: Array, forBytes bytes: Array, usingVariant variant: SecKeyAlgorithm, withKey key: SecKey) throws -> Bool { let pubKey = SecKeyCopyPublicKey(key)! var error: Unmanaged? // Perform the signature verification let result = SecKeyVerifySignature( pubKey, variant, Data(bytes) as CFData, Data(signature) as CFData, &error ) // Throw the error if we encountered one... if let error = error { throw error.takeRetainedValue() as Error } // return the result of the verification return result } private func secKeyEncrypt(_ bytes: Array, usingVariant variant: SecKeyAlgorithm, withKey key: SecKey) throws -> Data { let pubKey = SecKeyCopyPublicKey(key)! var error: Unmanaged? guard let encryptedData = SecKeyCreateEncryptedData(pubKey, variant, Data(bytes) as CFData, &error) else { throw NSError(domain: "Error Encrypting Data: \(error.debugDescription)", code: 0, userInfo: nil) } // Throw the error if we encountered one... if let error = error { throw error.takeRetainedValue() as Error } // return the result of the encryption return encryptedData as Data } private func secKeyDecrypt(_ bytes: Array, usingVariant variant: SecKeyAlgorithm, withKey key: SecKey) throws -> Data { var error: Unmanaged? guard let decryptedData = SecKeyCreateDecryptedData(key, variant, Data(bytes) as CFData, &error) else { throw NSError(domain: "Error Decrypting Data: \(error.debugDescription)", code: 0, userInfo: nil) } return (decryptedData as Data).drop { $0 == 0x00 } } } extension RSASecKeyTests { static func allTests() -> [(String, (RSASecKeyTests) -> () throws -> Void)] { let tests = [ ("testRSAExternalRepresentationPublic", testRSAExternalRepresentationPublic), ("testRSAExternalRepresentationPrivate", testRSAExternalRepresentationPrivate), ("testSecKeyExternalRepresentationPublic", testSecKeyExternalRepresentationPublic), ("testSecKeyExternalRepresentationPrivate", testSecKeyExternalRepresentationPrivate), ("testRSASecKeys", testRSASecKeys) ] return tests } } // - MARK: Test Fixture Generation Code extension RSASecKeyTests { /// This 'Test' generates an RSA Key and uses that key to sign and encrypt a series of messages that we can test against. /// /// It prints a `Fixture` object that can be copy and pasted / used in other tests. func testCreateTestFixture() throws { let keySize = 1024 let messages = [ "", "👋", "RSA Keys", "CryptoSwift RSA Keys!", "CryptoSwift RSA Keys are really cool! They support encrypting / decrypting messages, signing and verifying signed messages, and importing and exporting encrypted keys for use between sessions 🔐" ] print(messages.map { $0.bytes.count }) /// Generate a SecKey RSA Key let parameters: [CFString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeySizeInBits: keySize ] var error: Unmanaged? // Generate the RSA SecKey guard let rsaSecKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else { XCTFail("Key Generation Error: \(error.debugDescription)") return } // Extract the public key from the private RSA SecKey guard let rsaSecKeyPublic = SecKeyCopyPublicKey(rsaSecKey) else { XCTFail("Public Key Extraction Error") return } /// Let's grab the external representation of the public key var publicExternalRepError: Unmanaged? guard let publicRSASecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKeyPublic, &publicExternalRepError) as? Data else { XCTFail("Failed to copy external representation for RSA SecKey") return } /// Let's grab the external representation of the private key var privateExternalRepError: Unmanaged? guard let privateRSASecKeyRawRep = SecKeyCopyExternalRepresentation(rsaSecKey, &privateExternalRepError) as? Data else { XCTFail("Failed to copy external representation for RSA SecKey") return } var template = RSASecKeyTests.FixtureTemplate template = template.replacingOccurrences(of: "{{KEY_SIZE}}", with: "\(keySize)") template = template.replacingOccurrences(of: "{{PUBLIC_DER}}", with: "\(publicRSASecKeyRawRep.base64EncodedString())") template = template.replacingOccurrences(of: "{{PRIVATE_DER}}", with: "\(privateRSASecKeyRawRep.base64EncodedString())") var messageEntries: [String] = [] for message in messages { var messageTemplate = RSASecKeyTests.MessageTemplate messageTemplate = messageTemplate.replacingOccurrences(of: "{{PLAINTEXT_MESSAGE}}", with: message) let encryptedMessages = try encrypt(data: message.data(using: .utf8)!, with: rsaSecKeyPublic) messageTemplate = messageTemplate.replacingOccurrences(of: "{{ENCRYPTED_MESSAGES}}", with: encryptedMessages.joined(separator: ",\n\t\t ")) let signedMessages = try sign(message: message.data(using: .utf8)!, using: rsaSecKey) messageTemplate = messageTemplate.replacingOccurrences(of: "{{SIGNED_MESSAGES}}", with: signedMessages.joined(separator: ",\n\t\t ")) messageEntries.append(messageTemplate) } template = template.replacingOccurrences(of: "{{MESSAGE_TEMPLATES}}", with: "\(messageEntries.joined(separator: ",\n\t"))") print("\n**************************") print(" Test Fixture Output ") print("**************************\n") print(template) print("\n**************************") } private static let FixtureTemplate = """ static let RSA_{{KEY_SIZE}} = Fixture( keySize: {{KEY_SIZE}}, publicDER: \"\"\" {{PUBLIC_DER}} \"\"\", privateDER: \"\"\" {{PRIVATE_DER}} \"\"\", messages: [ {{MESSAGE_TEMPLATES}} ] ) """ private static let MessageTemplate = """ "{{PLAINTEXT_MESSAGE}}": ( encryptedMessage: [ {{ENCRYPTED_MESSAGES}} ], signedMessage: [ {{SIGNED_MESSAGES}} ] ) """ private func initSecKey(rawRepresentation rawKey: Data) throws -> SecKey { let attributes: [String: Any] = [ kSecAttrKeyType as String: kSecAttrKeyTypeRSA, kSecAttrKeyClass as String: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits as String: 1024, kSecAttrIsPermanent as String: false ] var error: Unmanaged? guard let secKey = SecKeyCreateWithData(rawKey as CFData, attributes as CFDictionary, &error) else { throw NSError(domain: "Error constructing SecKey from raw key data: \(error.debugDescription)", code: 0, userInfo: nil) } return secKey } // We don't support PSS yet so we skip these variants private func sign(message: Data, using key: SecKey) throws -> [String] { let algorithms: [SecKeyAlgorithm] = [ .rsaSignatureRaw, //.rsaSignatureDigestPSSSHA1, //.rsaSignatureDigestPSSSHA224, //.rsaSignatureDigestPSSSHA256, //.rsaSignatureDigestPSSSHA384, //.rsaSignatureDigestPSSSHA512, .rsaSignatureDigestPKCS1v15Raw, .rsaSignatureDigestPKCS1v15SHA1, .rsaSignatureDigestPKCS1v15SHA224, .rsaSignatureDigestPKCS1v15SHA256, .rsaSignatureDigestPKCS1v15SHA384, .rsaSignatureDigestPKCS1v15SHA512, //.rsaSignatureMessagePSSSHA1, //.rsaSignatureMessagePSSSHA224, //.rsaSignatureMessagePSSSHA256, //.rsaSignatureMessagePSSSHA384, //.rsaSignatureMessagePSSSHA512, .rsaSignatureMessagePKCS1v15SHA1, .rsaSignatureMessagePKCS1v15SHA224, .rsaSignatureMessagePKCS1v15SHA256, .rsaSignatureMessagePKCS1v15SHA384, .rsaSignatureMessagePKCS1v15SHA512, ] var sigs: [String] = [] for algo in algorithms { var error: Unmanaged? // Sign the data guard let signature = SecKeyCreateSignature( key, algo, message as CFData, &error ) as Data? else { print("\"\(algo.rawValue)\": \"nil\",") sigs.append("\"\(algo.rawValue)\": \"\"") continue } // Throw the error if we encountered one if let error = error { print("\"\(algo.rawValue)\": \"\(error.takeRetainedValue())\","); continue } // Append the signature sigs.append("\"\(algo.rawValue)\": \"\(signature.base64EncodedString())\"") } return sigs } private func encrypt(data: Data, with key: SecKey) throws -> [String] { let algorithms: [SecKeyAlgorithm] = [ .rsaEncryptionRaw, .rsaEncryptionPKCS1 ] var encryptions: [String] = [] for algo in algorithms { var error: Unmanaged? guard let encryptedData = SecKeyCreateEncryptedData(key, algo, data as CFData, &error) as? Data else { print("\"\(algo.rawValue)\": \"\(error?.takeRetainedValue().localizedDescription ?? "nil")\",") encryptions.append("\"\(algo.rawValue)\": \"\"") continue } encryptions.append("\"\(algo.rawValue)\": \"\(encryptedData.base64EncodedString())\"") } return encryptions } } #endif ================================================ FILE: Tests/CryptoSwiftTests/RSATests.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation import XCTest @testable import CryptoSwift final class RSATests: XCTestCase { func testSmallRSA() { /* * Example taken from the book "Understanding Cryptography" * * p = 3; q = 11; n = pq = 33; e = 3; d = 7 */ let n: Array = [33] let e: Array = [3] let d: Array = [7] let message: Array = [4] let expected: Array = [31] let rsa = RSA(n: n, e: e, d: d) XCTAssertEqual(rsa.keySize, 6, "key size is not correct") let encrypted = try! rsa.encrypt(message, variant: .unsafe) XCTAssertEqual(encrypted, expected, "small encrypt failed") let decrypted = try! rsa.decrypt(encrypted, variant: .unsafe) XCTAssertEqual(decrypted, message, "small decrypt failed") } func testRSA1() { /* * Taken from http://cryptomanager.com/tv.html * * 1. 1024-bit RSA bare exponentiation */ let n: Array = [ 0xF0, 0xC4, 0x2D, 0xB8, 0x48, 0x6F, 0xEB, 0x95, 0x95, 0xD8, 0xC7, 0x8F, 0x90, 0x8D, 0x04, 0xA9, 0xB6, 0xC8, 0xC7, 0x7A, 0x36, 0x10, 0x5B, 0x1B, 0xF2, 0x75, 0x53, 0x77, 0xA6, 0x89, 0x3D, 0xC4, 0x38, 0x3C, 0x54, 0xEC, 0x6B, 0x52, 0x62, 0xE5, 0x68, 0x8E, 0x5F, 0x9D, 0x9D, 0xD1, 0x64, 0x97, 0xD0, 0xE3, 0xEA, 0x83, 0x3D, 0xEE, 0x2C, 0x8E, 0xBC, 0xD1, 0x43, 0x83, 0x89, 0xFC, 0xCA, 0x8F, 0xED, 0xE7, 0xA8, 0x8A, 0x81, 0x25, 0x7E, 0x8B, 0x27, 0x09, 0xC4, 0x94, 0xD4, 0x2F, 0x72, 0x3D, 0xEC, 0x2E, 0x0B, 0x5C, 0x09, 0x73, 0x1C, 0x55, 0x0D, 0xCC, 0x9D, 0x7E, 0x75, 0x25, 0x89, 0x89, 0x1C, 0xBB, 0xC3, 0x02, 0x13, 0x07, 0xDD, 0x91, 0x8E, 0x10, 0x0B, 0x34, 0xC0, 0x14, 0xA5, 0x59, 0xE0, 0xE1, 0x82, 0xAF, 0xB2, 0x1A, 0x72, 0xB3, 0x07, 0xCC, 0x39, 0x5D, 0xEC, 0x99, 0x57, 0x47 ] let e: Array = [ 0x01, 0x00, 0x01 ] let d: Array = [ 0x24, 0x89, 0x10, 0x8B, 0x0B, 0x6A, 0xF8, 0x6B, 0xED, 0x9E, 0x44, 0xC2, 0x33, 0x64, 0x42, 0xD5, 0xE2, 0x27, 0xDB, 0xA5, 0x5E, 0xF8, 0xE2, 0x6A, 0x7E, 0x43, 0x71, 0x94, 0x11, 0x90, 0x77, 0xF0, 0x03, 0xBC, 0x9C, 0x02, 0x78, 0x52, 0xBB, 0x31, 0x26, 0xC9, 0x9C, 0x16, 0xD5, 0xF1, 0x05, 0x7B, 0xC8, 0x36, 0x1D, 0xCB, 0x26, 0xA5, 0xB2, 0xDB, 0x42, 0x29, 0xDB, 0x3D, 0xE5, 0xBD, 0x97, 0x9B, 0x2E, 0x59, 0x7D, 0x19, 0x16, 0xD7, 0xBB, 0xC9, 0x27, 0x46, 0xFC, 0x07, 0x59, 0x5C, 0x76, 0xB4, 0x4B, 0x39, 0xA4, 0x76, 0xA6, 0x5C, 0x86, 0xF0, 0x86, 0xDC, 0x92, 0x83, 0xCA, 0x6D, 0x1E, 0xEF, 0xC1, 0x49, 0x15, 0x98, 0x2F, 0x9C, 0x4C, 0xED, 0x5F, 0x62, 0xA9, 0xFF, 0x3B, 0xE2, 0x42, 0x18, 0xA9, 0x93, 0x57, 0xB5, 0xB6, 0x5C, 0x3B, 0x10, 0xAE, 0xB3, 0x67, 0xE9, 0x11, 0xEB, 0x9E, 0x21 ] let message: Array = [ 0x11, 0x22, 0x33, 0x44 ] let expected: Array = [ 0x50, 0x5B, 0x09, 0xBD, 0x5D, 0x0E, 0x66, 0xD7, 0xC8, 0x82, 0x9F, 0x5B, 0x47, 0x3E, 0xD3, 0x4D, 0xB5, 0xCF, 0xDB, 0xB5, 0xD5, 0x8C, 0xE7, 0x83, 0x29, 0xC8, 0xBF, 0x85, 0x20, 0xE4, 0x86, 0xD3, 0xC4, 0xCF, 0x9B, 0x70, 0xC6, 0x34, 0x65, 0x94, 0x35, 0x80, 0x80, 0xF4, 0x3F, 0x47, 0xEE, 0x86, 0x3C, 0xFA, 0xF2, 0xA2, 0xE5, 0xF0, 0x3D, 0x1E, 0x13, 0xD6, 0xFE, 0xC5, 0x7D, 0xFB, 0x1D, 0x55, 0x22, 0x24, 0xC4, 0x61, 0xDA, 0x41, 0x1C, 0xFE, 0x5D, 0x0B, 0x05, 0xBA, 0x87, 0x7E, 0x3A, 0x42, 0xF6, 0xDE, 0x4D, 0xA4, 0x6A, 0x96, 0x5C, 0x9B, 0x69, 0x5E, 0xE2, 0xD5, 0x0E, 0x40, 0x08, 0x94, 0x06, 0x1C, 0xB0, 0xA2, 0x1C, 0xA3, 0xA5, 0x24, 0xB4, 0x07, 0xE9, 0xFF, 0xBA, 0x87, 0xFC, 0x96, 0x6B, 0x3B, 0xA9, 0x45, 0x90, 0x84, 0x9A, 0xEB, 0x90, 0x8A, 0xAF, 0xF4, 0xC7, 0x19, 0xC2, 0xE4 ] let rsa = RSA(n: n, e: e, d: d) XCTAssertEqual(rsa.keySize, 1024, "key size is not correct") let encrypted = try! rsa.encrypt(message, variant: .unsafe) XCTAssertEqual(encrypted, expected, "encrypt failed") let decrypted = try! rsa.decrypt(encrypted, variant: .unsafe) XCTAssertEqual(decrypted, message, "decrypt failed") } func testRSA2() { /* * Taken from http://cryptomanager.com/tv.html * * 2. 2048-bit PKCS V. 1.5 enciphering. */ let n: Array = [ 0xF7, 0x48, 0xD8, 0xD9, 0x8E, 0xD0, 0x57, 0xCF, 0x39, 0x8C, 0x43, 0x7F, 0xEF, 0xC6, 0x15, 0xD7, 0x57, 0xD3, 0xF8, 0xEC, 0xE6, 0xF2, 0xC5, 0x80, 0xAE, 0x07, 0x80, 0x76, 0x8F, 0x9E, 0xC8, 0x3A, 0xAA, 0x08, 0x1F, 0xF0, 0x9E, 0x53, 0x17, 0xED, 0x60, 0x99, 0xC6, 0x3F, 0xD1, 0x5C, 0xFE, 0x11, 0x17, 0x2F, 0x78, 0x90, 0x8C, 0xD5, 0x8C, 0x03, 0xAE, 0xC9, 0x3A, 0x48, 0x1F, 0xF5, 0x0E, 0x17, 0x22, 0x04, 0xAF, 0xED, 0xFC, 0x1F, 0x16, 0xAF, 0xDB, 0x99, 0x0A, 0xAB, 0x45, 0xBE, 0x19, 0x0B, 0xC1, 0x92, 0x59, 0xBD, 0x4A, 0x1B, 0xFC, 0xDF, 0xBE, 0x2A, 0x29, 0x8B, 0x3C, 0x0E, 0x31, 0x8F, 0x78, 0xA3, 0x39, 0x19, 0x88, 0x23, 0x28, 0xDA, 0xCA, 0xC8, 0x5C, 0xB3, 0x5A, 0x0D, 0xE5, 0x37, 0xB1, 0x63, 0x76, 0x97, 0x52, 0x17, 0xE5, 0xA5, 0xEA, 0xAF, 0x98, 0x26, 0x6B, 0x58, 0x8C, 0x2D, 0xBA, 0xFD, 0x0B, 0xE3, 0x71, 0xC3, 0x49, 0x89, 0xCB, 0x36, 0xE6, 0x23, 0xD7, 0x5E, 0xFF, 0xED, 0xBE, 0x4A, 0x95, 0x1A, 0x68, 0x40, 0x98, 0x2B, 0xC2, 0x79, 0xB3, 0x0F, 0xCD, 0x41, 0xDA, 0xC8, 0x7C, 0x00, 0x74, 0xD4, 0x62, 0xF1, 0x01, 0x29, 0x00, 0xB8, 0x97, 0x3B, 0x46, 0xAD, 0xC7, 0xEA, 0xC0, 0x17, 0x70, 0xDF, 0xC6, 0x32, 0xEA, 0x96, 0x7F, 0x94, 0x71, 0xE9, 0x78, 0x98, 0x31, 0xF3, 0xA4, 0x10, 0x73, 0x0F, 0xF9, 0x14, 0x34, 0x8B, 0xE1, 0x11, 0x86, 0x3C, 0x13, 0x37, 0x63, 0x01, 0x07, 0x97, 0x56, 0xA1, 0x47, 0xD8, 0x01, 0x03, 0xCE, 0x9F, 0xA6, 0x88, 0xA3, 0x38, 0xE2, 0x2B, 0x2D, 0x91, 0x6C, 0xAD, 0x42, 0xD6, 0x73, 0xC9, 0xD0, 0x0F, 0x08, 0x21, 0x4D, 0xE5, 0x44, 0xF5, 0xDE, 0x81, 0x2A, 0x9A, 0x94, 0x91, 0x89, 0x07, 0x8B, 0x2B, 0xDA, 0x14, 0xB2, 0x8C, 0xA6, 0x2F ] let e: Array = [ 0x01, 0x00, 0x01 ] let d: Array = [ 0x1C, 0xBC, 0x9A, 0x76, 0xAD, 0xE2, 0x08, 0x52, 0x4C, 0x9D, 0xC0, 0x3A, 0x5D, 0xE2, 0xE7, 0x26, 0xDF, 0x4E, 0x02, 0xDF, 0x84, 0xF7, 0x31, 0x7C, 0x82, 0xBC, 0xDC, 0x70, 0xEA, 0xBF, 0xC9, 0x05, 0x08, 0x3D, 0x69, 0x78, 0xCC, 0xED, 0x5B, 0x1A, 0x7A, 0xDF, 0x63, 0xEA, 0x86, 0xAA, 0x07, 0xDC, 0x74, 0x95, 0x4F, 0xAD, 0x7C, 0xB0, 0x54, 0x55, 0x19, 0x3A, 0xC9, 0x4B, 0x18, 0x6B, 0xA1, 0xF7, 0x8E, 0x3C, 0x7D, 0x35, 0x6A, 0xD7, 0x32, 0x0B, 0xBD, 0xB9, 0x4B, 0x44, 0x1C, 0x16, 0xBB, 0x52, 0x62, 0x6C, 0x5F, 0x81, 0x5F, 0xDB, 0x60, 0xC7, 0x9F, 0x91, 0xC6, 0xC2, 0x27, 0x78, 0x7E, 0xC9, 0xED, 0x7B, 0x0A, 0x67, 0xAD, 0x2A, 0x68, 0xD5, 0x04, 0x3B, 0xC4, 0x8A, 0x13, 0x2D, 0x0A, 0x36, 0x2E, 0xA7, 0x20, 0x60, 0xF5, 0x69, 0x51, 0x86, 0xB6, 0x7F, 0x31, 0x6F, 0x45, 0x8A, 0x44, 0xBF, 0xD1, 0x40, 0x3D, 0x93, 0xA9, 0xB9, 0x12, 0xCB, 0xB5, 0x98, 0x15, 0x91, 0x6A, 0x14, 0xA2, 0xBA, 0xD4, 0xF9, 0xA1, 0xED, 0x57, 0x8E, 0xBD, 0x2B, 0x5D, 0x47, 0x2F, 0x62, 0x3B, 0x4B, 0xB5, 0xF9, 0xB8, 0x0B, 0x93, 0x57, 0x2B, 0xEA, 0x61, 0xBD, 0x10, 0x68, 0x09, 0x4E, 0x41, 0xE8, 0x39, 0x0E, 0x2E, 0x28, 0xA3, 0x51, 0x43, 0x3E, 0xDD, 0x1A, 0x09, 0x9A, 0x8C, 0x6E, 0x68, 0x92, 0x60, 0x4A, 0xEF, 0x16, 0x3A, 0x43, 0x9B, 0x1C, 0xAE, 0x6A, 0x09, 0x5E, 0x68, 0x94, 0x3C, 0xA6, 0x7B, 0x18, 0xC8, 0xDC, 0x7F, 0x98, 0xCC, 0x5F, 0x8E, 0xFA, 0x22, 0xBB, 0xC8, 0x7D, 0x2E, 0x73, 0x57, 0x83, 0xD2, 0xBA, 0xA3, 0x8F, 0x4C, 0x17, 0xD5, 0xED, 0x0C, 0x58, 0x36, 0x6D, 0xCE, 0xF5, 0xE8, 0x52, 0xDD, 0x3D, 0x6E, 0x0F, 0x63, 0x72, 0x95, 0x43, 0xE2, 0x63, 0x8B, 0x29, 0x14, 0xD7, 0x2A, 0x01 ] let message: Array = [ 0x11, 0x22, 0x33, 0x44 ] let expected: Array = [ 0xEE, 0x69, 0x09, 0x9A, 0xFD, 0x9F, 0x99, 0xD6, 0x06, 0x5D, 0x65, 0xE1, 0x5F, 0x90, 0xB9, 0x23, 0x7C, 0x16, 0x98, 0x7D, 0x48, 0x72, 0xE2, 0xB9, 0x94, 0xED, 0x2B, 0x9E, 0x56, 0x85, 0xF9, 0xBA, 0x48, 0x9A, 0xB9, 0x36, 0xCC, 0x1E, 0x3D, 0xFD, 0x15, 0xB3, 0x5F, 0xEE, 0x21, 0x53, 0x6F, 0x8C, 0x22, 0x20, 0xAE, 0x43, 0x21, 0x7D, 0x91, 0xD8, 0x1C, 0x9E, 0xD0, 0x1D, 0xE5, 0xBA, 0xEE, 0xF4, 0xEF, 0xC7, 0x21, 0xD7, 0x0D, 0x67, 0xB5, 0x16, 0x6E, 0x43, 0xD8, 0x27, 0x24, 0xF3, 0x9B, 0xF0, 0xBD, 0x19, 0x7C, 0x31, 0xE7, 0x48, 0x51, 0x8D, 0xEE, 0x63, 0xEC, 0x10, 0x98, 0x7A, 0x08, 0x39, 0x0B, 0x15, 0xCC, 0x41, 0x57, 0x67, 0x7C, 0x54, 0x22, 0x6A, 0x8B, 0x04, 0xB4, 0x76, 0x84, 0xAE, 0xDD, 0x02, 0xB4, 0x8C, 0x8E, 0xD4, 0x8A, 0x44, 0xBD, 0x13, 0x53, 0x97, 0xAC, 0x28, 0x69, 0x76, 0x9B, 0x68, 0xC7, 0xD3, 0xBF, 0xAC, 0xDB, 0x72, 0xAF, 0xCD, 0x74, 0x42, 0xC2, 0x25, 0x17, 0xE0, 0x44, 0x99, 0x6C, 0xB6, 0x8E, 0x0A, 0x31, 0x1D, 0xF5, 0xD6, 0xD2, 0xD2, 0x86, 0x37, 0x25, 0x56, 0xF0, 0x19, 0x31, 0x66, 0xCC, 0x36, 0x4E, 0x65, 0x4E, 0xF4, 0x05, 0xDD, 0x22, 0xFB, 0xE5, 0x84, 0xDB, 0xF6, 0x0F, 0x05, 0x52, 0x96, 0x06, 0x68, 0xFB, 0x69, 0x52, 0x2C, 0x1B, 0x52, 0x64, 0xF1, 0x94, 0xFA, 0xC9, 0xF3, 0x56, 0x22, 0xE9, 0x82, 0x27, 0x63, 0x8F, 0xF2, 0x8B, 0x91, 0x0D, 0x8C, 0xC9, 0x0E, 0x50, 0x11, 0x02, 0x12, 0x12, 0xC9, 0x6C, 0x64, 0xC8, 0x58, 0x20, 0x87, 0x7A, 0x7D, 0x15, 0x59, 0x23, 0x5E, 0x99, 0xC3, 0x2A, 0xBE, 0xF3, 0x3D, 0x95, 0xE2, 0x8E, 0x18, 0xCC, 0xA3, 0x44, 0x2E, 0x6E, 0x3A, 0x43, 0x2F, 0xFF, 0xEA, 0x10, 0x10, 0x4A, 0x8E, 0xEE, 0x94, 0xC3, 0x62 ] let rsa = RSA(n: n, e: e, d: d) XCTAssertEqual(rsa.keySize, 2048, "key size is not correct") let encrypted = try! rsa.encrypt(message, variant: .unsafe) XCTAssertEqual(encrypted, expected, "encrypt failed") let decrypted = try! rsa.decrypt(encrypted, variant: .unsafe) XCTAssertEqual(decrypted, message, "decrypt failed") } func testGenerateKeyPair() { /* * To test key generation and its validity */ let message: Array = [ 0x11, 0x22, 0x33, 0x44 ] do { let rsa = try RSA(keySize: 2048) // Sometimes the modulus size is 2047 bits, but it's okay (with two 1024 bits primes) //XCTAssertEqual(rsa.keySize, 2048, "key size is not correct") let decrypted = try rsa.decrypt(rsa.encrypt(message, variant: .unsafe), variant: .unsafe) XCTAssertEqual(decrypted, message, "encrypt+decrypt failed") } catch { XCTFail("\(error)") } } /// This test walks through the PKCS1 Encryption scheme manually /// /// This test enforces that /// 1) We can decrypt a message appropriately using the PKCS1v15 Encryption Scheme /// - Note: This signature scheme is non-deterministic so we can only test that decryption results in the expected message. func testRSAPKCS1_v15EncryptionManual() throws { let fixture = TestFixtures.RSA_1024 guard let privateDERData = Data(base64Encoded: fixture.privateDER) else { XCTFail("Invalid Base64String Public DER") return } // Import RSA Key let rsa = try RSA(rawRepresentation: privateDERData) let expectedMessage = "RSA Keys" let messageToDecrypt = Data(base64Encoded: fixture.messages[expectedMessage]!.encryptedMessage["algid:encrypt:RSA:PKCS1"]!)!.byteArray // Decrypt the data let decrypted = BigUInteger(Data(messageToDecrypt)).power(rsa.d!, modulus: rsa.n).serialize().byteArray let unpadded = Padding.eme_pkcs1v15.remove(from: [0x00] + decrypted, blockSize: rsa.keySize) XCTAssertEqual(expectedMessage, String(data: Data(unpadded), encoding: .utf8), "Failed to decrypt the message") } /// This test focuses on ensuring that the encryption & decryption round trip works as expected. /// /// This test enforces that /// 1) We can encrypt and then decrypt a random integer /// 2) We recover the original integer after decryption func testEncryptDecryptRoundTripRandomIntegers() { do { let rsa = try RSA(keySize: 1024) for _ in 0..<5 { let message = BigUInteger.randomInteger(withMaximumWidth: 256).serialize().byteArray let decrypted = try rsa.decrypt(rsa.encrypt(message, variant: .pksc1v15), variant: .pksc1v15) XCTAssertEqual(decrypted, message, "encrypt+decrypt failed") } } catch { XCTFail("\(error)") } } /// This test focuses on ensuring that the signature & signature verification works as expected. /// /// This test enforces that /// 1) We can sign and then verify a random integer /// 2) if we modify the signature or the message in any way, the verify function returns false or throws an error. func testSignatureVerificationRandomIntegers() { do { let rsa = try RSA(keySize: 1024) for _ in 0..<5 { let message = BigUInteger.randomInteger(withMaximumWidth: 256).serialize().byteArray let signature = try rsa.sign(message, variant: .message_pkcs1v15_SHA256) XCTAssertTrue(try rsa.verify(signature: signature, for: message, variant: .message_pkcs1v15_SHA256), "Failed to Verify Signature for `\(message)`") XCTAssertFalse(try rsa.verify(signature: signature, for: message.shuffled())) XCTAssertFalse(try rsa.verify(signature: signature.shuffled(), for: message)) XCTAssertThrowsError(try rsa.verify(signature: signature.dropLast(), for: message)) } } catch { XCTFail("\(error)") } } /// This test walks through the PKCS1 Signature scheme manually /// /// This test enforces that /// 1) We can prepare and sign a message appropriately using the PKCS1v15 Signature Scheme /// - Note: This signature scheme is deterministic so we can test against a known static value func testRSAPKCS1_v15SignatureManual() throws { let fixture = TestFixtures.RSA_1024 guard let privateDERData = Data(base64Encoded: fixture.privateDER) else { XCTFail("Invalid Base64String Public DER") return } // Import RSA Key let rsa = try RSA(rawRepresentation: privateDERData) let message = "CryptoSwift RSA Keys!" /// 1. Apply the hash function to the message M to produce a hash let hashedMessage = SHA2(variant: .sha256).calculate(for: message.bytes) /// 2. Encode the algorithm ID for the hash function and the hash value into an ASN.1 value of type DigestInfo /// PKCS#1_15 DER Structure (OID == sha256WithRSAEncryption) let asn: ASN1.Node = .sequence(nodes: [ .sequence(nodes: [ .objectIdentifier(data: Data(Array(arrayLiteral: 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01))), .null ]), .octetString(data: Data(hashedMessage)) ]) let t = ASN1.Encoder.encode(asn) /// 3. If emLen < tLen + 11, output "intended encoded message length too short" and stop if rsa.keySizeBytes < t.count + 11 { throw RSA.Error.invalidMessageLengthForSigning } /// 4. Generate an octet string PS consisting of emLen - tLen - 3 /// octets with hexadecimal value 0xff. The length of PS will be /// at least 8 octets. /// 5. Concatenate PS, the DER encoding T, and other padding to form /// the encoded message EM as EM = 0x00 || 0x01 || PS || 0x00 || T. let padded = EMSAPKCS1v15Padding().add(to: t, blockSize: rsa.keySizeBytes) // Sign the data let signedData = BigUInteger(Data(padded)).power(rsa.d!, modulus: rsa.n).serialize().byteArray // Ensure the signed data matches that of our test fixture XCTAssertEqual(signedData.toBase64(), fixture.messages[message]!.signedMessage["algid:sign:RSA:message-PKCS1v15:SHA256"], "Failed to correctly sign the data") } /// Tests invalid message length for signatures /// /// This test enforces that /// 1) The signature method throws an error when the data you're trying to sign is of an invalid length while using the `digest` variant /// - The `digest` variants skip the hashing step /// 2) The signature method hashes and signs the message appropriately when using the `message` variant func testRSAPKCS1_v15SignaturesLength() throws { let fixture = TestFixtures.RSA_1024 guard let privateDERData = Data(base64Encoded: fixture.privateDER) else { XCTFail("Invalid Base64String Public DER") return } // Import RSA Key let rsa = try RSA(rawRepresentation: privateDERData) let message = Data("This is a long message that if not hashed, will be tool large to safely sign / encrypt, therefore it should throw an error instead of resulting in a signature".utf8).byteArray // The unhashed message is too long to sign, we expect an error to be thrown... XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA1)) XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA224)) XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA256)) XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA384)) XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA512)) XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA512_224)) XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA512_256)) XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA3_256)) XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA3_384)) XCTAssertThrowsError(try rsa.sign(message, variant: .digest_pkcs1v15_SHA3_512)) // But if we hash the message first, then the signature works as expected... XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA1)) XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA224)) XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA256)) XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA384)) XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA512)) XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA512_224)) XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA512_256)) XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA3_256)) XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA3_384)) XCTAssertNoThrow(try rsa.sign(message, variant: .message_pkcs1v15_SHA3_512)) } /// This test uses the Fixtures (generated using Apple's `Security` framework) to test the entirety of an RSA keys functionality /// /// - Note: These Fixtures were generated using the `testCreateTestFixture` function in `RSASecKeyTests` file. /// /// For each fixture in the `fixtures` array, we test... /// 1) Importing the RSA Public DER Representation /// - Ensure the key was imported correctly /// - Ensure that we can export the public key in it's DER representation and that it matches the expected data /// - Ensure that we are able to encrypt the messages and that we receive the same data when testing deterministic encryption variants /// - Ensure that attempting to decrypt a message without a private key throws and error /// - Ensure that attempting to sign data without a private key throws an error /// - Ensure that we can verify that the signed data was in fact signed with this public keys corresponding private key /// 2) Importing the RSA Private DER Representation /// - Ensure the key was imported correctly /// - Ensure that we can export the public key in it's DER representation and that it matches the expected data /// - Ensure that we can export the private key in it's DER representation and that it matches the expected data /// - Ensure that we are able to encrypt the messages and that we receive the same data when testing deterministic encryption variants /// - Ensure that we are able to decrypt the messages and that we recover the original plaintext message /// - Ensure that we are able to sign the plaintext messages and that it produces the expected data /// - Ensure that we can verify that the signed data was in fact signed with this public keys corresponding private key func testRSAKeys() { // These tests can take a very long time. Therefore the larger keys have been commented out in order to make the tests complete a little quicker. let fixtures = [TestFixtures.RSA_1023, TestFixtures.RSA_1024, TestFixtures.RSA_1056, TestFixtures.RSA_2048] //, TestFixtures.RSA_3072, TestFixtures.RSA_4096] do { /// Public Key Functionality for fixture in fixtures { print("Testing RSA<\(fixture.keySize)>:Public Key Fixture") let tic = DispatchTime.now().uptimeNanoseconds guard let publicDERData = Data(base64Encoded: fixture.publicDER) else { XCTFail("Invalid Base64String Public DER") return } // Import RSA Key let rsa = try RSA(rawRepresentation: publicDERData) // Ensure that the Key Size is correct XCTAssertEqual(rsa.keySize, fixture.keySize, "\(rsa)::Invalid Key Size after import") // Ensure that we do not have a private key by checking the private exponent XCTAssertNil(rsa.d, "\(rsa)::Private exponent not nil ") // Ensure the public external representation matches the fixture XCTAssertEqual(try rsa.publicKeyExternalRepresentation(), Data(base64Encoded: fixture.publicDER), "\(rsa)::Public Key external Representation doesn't match fixture") // Ensure externalRepresentation results in the publicDER XCTAssertEqual(try rsa.externalRepresentation(), Data(base64Encoded: fixture.publicDER), "\(rsa)::Public Key external Representation doesn't match fixture") for message in fixture.messages { // Ensure each encryption algo matches the fixture for test in message.value.encryptedMessage { guard let variant = encryptionAlgoToVariant(test.key) else { print("Warning::RSA<\(fixture.keySize)>::Skipping Encryption Algorithm \(test.key)") continue } if variant == .raw { if test.value == "" { XCTAssertThrowsError(try rsa.encrypt(message.key.bytes, variant: variant), "Encryption<\(test.key)>::Did not throw error while encrypting `\(message.key)`") } else { // The Raw encryption method is deterministic so we can test that encrypting the message matches the data in the test fixture... let encrypted = try rsa.encrypt(message.key.bytes, variant: variant) XCTAssertEqual(encrypted.toHexString(), Data(base64Encoded: message.value.encryptedMessage["algid:encrypt:RSA:raw"]!)!.byteArray.toHexString(), "Encryption<\(test.key)>::Failed to encrypt the message `\(message.key)`") // Decryption requires access to the Private Key, therefore attempting to decrypt with only a public key should throw an error XCTAssertThrowsError(try rsa.decrypt(Data(base64Encoded: message.value.encryptedMessage["algid:encrypt:RSA:raw"]!)!.byteArray), "Encryption<\(test.key)>::Did not throw error while decrypting `\(message.key)`") } } else { // Sometimes the message is too long to be safely encrypted by our key. When this happens we should encounter an error and our test value should be empty. if test.value == "" { XCTAssertThrowsError(try rsa.encrypt(message.key.bytes, variant: variant), "Encryption<\(test.key)>::Did not throw error while encrypting `\(message.key)`") } else { // We should be able to encrypt the data using just the public key let encrypted = try rsa.encrypt(test.key.bytes, variant: variant) XCTAssertNotEqual(encrypted, test.key.bytes) // Decryption requires a private key, so this should throw an error XCTAssertThrowsError(try rsa.decrypt(encrypted, variant: variant), "Encryption<\(test.key)>::Did not throw error while decrypting `\(message.key)`") } } } // Ensure each signature algo matches the fixture for test in message.value.signedMessage { guard let variant = signatureAlgoToVariant(test.key) else { print("Warning::RSA<\(fixture.keySize)>::Skipping Signature Algorithm \(test.key)") continue } // Signing data requires access to the private key, therefore this should throw an error when called on a public key XCTAssertThrowsError(try rsa.sign(message.key.bytes, variant: variant), "Signature<\(test.key)>::Did not throw error") // Sometimes the message is too long to be safely signed by our key. When this happens we should encounter an error and our test value should be empty. if test.value == "" { XCTAssertThrowsError(try rsa.verify(signature: Data(base64Encoded: test.value)!.byteArray, for: message.key.bytes, variant: variant), "Signature<\(test.key)>::Did not throw error") } else { // Ensure the signature is valid for the test fixtures rawMessage XCTAssertTrue(try rsa.verify(signature: Data(base64Encoded: test.value)!.byteArray, for: message.key.bytes, variant: variant), "Signature<\(test.key)>::Verification Failed") // Ensure a modified message results in a false / invalid signature verification XCTAssertFalse(try rsa.verify(signature: Data(base64Encoded: test.value)!.byteArray, for: message.key.bytes + [0x00], variant: variant), "Signature<\(test.key)>::Verified a signature for an incorrect message `\(message.key)`") if !message.key.bytes.isEmpty { XCTAssertFalse(try rsa.verify(signature: Data(base64Encoded: test.value)!.byteArray, for: message.key.bytes.dropLast(), variant: variant), "Signature<\(test.key)>::Verified a signature for an incorrect message `\(message.key)`") } // Ensure a modified signature results in a false / invalid signature verification (we replace the last element with a 1 in case the signature is all 0's) XCTAssertFalse(try rsa.verify(signature: Data(base64Encoded: test.value)!.byteArray.shuffled().dropLast() + [0x01], for: message.key.bytes, variant: variant), "Signature<\(test.key)>::Verified a False signature for message `\(message.key)`") // Ensure an invalid signature results in an error being thrown XCTAssertThrowsError(try rsa.verify(signature: Data(base64Encoded: test.value)!.byteArray.dropLast(), for: message.key.bytes, variant: variant), "Signature<\(test.key)>::Verified a False signature for message `\(message.key)`") } } } print("RSA<\(fixture.keySize)>Public Test took \(DispatchTime.now().uptimeNanoseconds - tic)ns") } /// Private Key Functionality for fixture in fixtures { print("Testing RSA<\(fixture.keySize)>:Private Key Fixture") let tic = DispatchTime.now().uptimeNanoseconds guard let privateDERData = Data(base64Encoded: fixture.privateDER) else { XCTFail("Invalid Base64String Private DER") return } // Import RSA Key let rsa = try RSA(rawRepresentation: privateDERData) // Ensure that the Key Size is correct XCTAssertEqual(rsa.keySize, fixture.keySize, "\(rsa)::Invalid Key Size after import") // Ensure that we have a private key by checking the private exponent XCTAssertNotNil(rsa.d, "\(rsa)::Failed to import private exponent from Private Key external representation") // Ensure the public external representation matches the fixture XCTAssertEqual(try rsa.publicKeyExternalRepresentation(), Data(base64Encoded: fixture.publicDER), "\(rsa)::Public Key external Representation doesn't match fixture") // Ensure the private external representation matches the fixture XCTAssertEqual(try rsa.externalRepresentation(), Data(base64Encoded: fixture.privateDER), "\(rsa)::Private Key external representation doesn't match fixture") for message in fixture.messages { // Ensure each encryption algo matches the fixture for test in message.value.encryptedMessage { guard let variant = encryptionAlgoToVariant(test.key) else { print("Warning::RSA<\(fixture.keySize)>::Skipping Encryption Algorithm \(test.key)") continue } //print("Testing \(rsa) Encryption<\(variant)> - Encrypting Message `\(message.key)`") if variant == .raw { if test.value == "" { XCTAssertThrowsError(try rsa.encrypt(message.key.bytes, variant: variant)) } else { // The Raw encryption method is deterministic so we can test that encrypting the message matches the data in the test fixture... let encrypted = try rsa.encrypt(message.key.bytes, variant: variant) XCTAssertEqual(encrypted.toHexString(), Data(base64Encoded: message.value.encryptedMessage["algid:encrypt:RSA:raw"]!)!.byteArray.toHexString(), "Encryption<\(test.key)>::Failed to encrypt the message `\(message.key)`") // Decrypt the fixtures encrypted message and ensure it matches the plaintext message let decrypted = try rsa.decrypt(Data(base64Encoded: test.value)!.byteArray, variant: variant) XCTAssertEqual(String(data: Data(decrypted), encoding: .utf8), message.key, "Encryption<\(test.key)>::Failed to decrypt the message `\(message.key)`") } } else { if test.value == "" { XCTAssertThrowsError(try rsa.encrypt(message.key.bytes, variant: variant), "Encryption<\(test.key)>::Encrypted invalid message `\(message.key)`. Should have thrown an error...") } else { // We should be able to encrypt the data using just the public key let encrypted = try rsa.encrypt(test.key.bytes, variant: variant) XCTAssertNotEqual(encrypted, test.key.bytes) // Ensure we can decrypt the data and that it matches the original message let decrypted = try rsa.decrypt(encrypted, variant: variant) XCTAssertEqual(test.key.bytes, decrypted, "Encryption<\(test.key)>::Failed to decrypt the message `\(message.key)`") // Ensure the encrypted fixture can be decrypted and results in the expected raw message let decryptedFixture = try rsa.decrypt(Data(base64Encoded: test.value)!.byteArray, variant: variant) XCTAssertEqual(decryptedFixture, message.key.bytes, "Encryption<\(test.key)>::Failed to decrypt the message `\(message.key)`") } } } // Ensure each signature algo matches the fixture for test in message.value.signedMessage { guard let variant = signatureAlgoToVariant(test.key) else { print("Warning::RSA<\(fixture.keySize)>::Skipping Signature Algorithm \(test.key)") continue } // Our Message is too long for some of our hashing / padding schemes. When this happens we should encouter an error and our test value should be empty. if test.value == "" { XCTAssertThrowsError(try rsa.sign(message.key.bytes, variant: variant), "Signature<\(test.key)>::Did not throw error") } else { let signature = try rsa.sign(message.key.bytes, variant: variant) XCTAssertEqual(signature, Data(base64Encoded: test.value)?.byteArray, "Signature<\(test.key)>::Signature does not match fixture") // Ensure the signature is valid for the test fixtures rawMessage XCTAssertTrue(try rsa.verify(signature: Data(base64Encoded: test.value)!.byteArray, for: message.key.bytes, variant: variant), "Signature<\(test.key)>::Verification Failed") // Ensure a modified message results in a false / invalid signature verification XCTAssertFalse(try rsa.verify(signature: Data(base64Encoded: test.value)!.byteArray, for: message.key.bytes + [0x00], variant: variant), "Signature<\(test.key)>::Verified a signature for an incorrect message `\(message.key)`") if !message.key.bytes.isEmpty { XCTAssertFalse(try rsa.verify(signature: Data(base64Encoded: test.value)!.byteArray, for: message.key.bytes.dropLast(), variant: variant), "Signature<\(test.key)>::Verified a signature for an incorrect message `\(message.key)`") } // Ensure a modified signature results in a false / invalid signature verification (we replace the last element with a 1 in case the signature is all 0's) XCTAssertFalse(try rsa.verify(signature: Data(base64Encoded: test.value)!.byteArray.shuffled().dropLast() + [0x01], for: message.key.bytes, variant: variant), "Signature<\(test.key)>::Verified a False signature for message `\(message.key)`") // Ensure an invalid signature results in an error being thrown XCTAssertThrowsError(try rsa.verify(signature: Data(base64Encoded: test.value)!.byteArray.dropLast(), for: message.key.bytes, variant: variant), "Signature<\(test.key)>::Verified a False signature for message `\(message.key)`") } } } print("RSA<\(fixture.keySize)>Private Test took \(DispatchTime.now().uptimeNanoseconds - tic)ns") } } catch { print(error) XCTFail(error.localizedDescription) } } /// Converts an algorithm string key from our test fixture into an RSA.SignatureVariant enum case private func signatureAlgoToVariant(_ algoString: String) -> RSA.SignatureVariant? { switch algoString { case "algid:sign:RSA:raw": return .raw case "algid:sign:RSA:digest-PKCS1v15": return .digest_pkcs1v15_RAW case "algid:sign:RSA:digest-PKCS1v15:SHA1": return .digest_pkcs1v15_SHA1 case "algid:sign:RSA:digest-PKCS1v15:SHA224": return .digest_pkcs1v15_SHA224 case "algid:sign:RSA:digest-PKCS1v15:SHA256": return .digest_pkcs1v15_SHA256 case "algid:sign:RSA:digest-PKCS1v15:SHA384": return .digest_pkcs1v15_SHA384 case "algid:sign:RSA:digest-PKCS1v15:SHA512": return .digest_pkcs1v15_SHA512 case "algid:sign:RSA:message-PKCS1v15:SHA1": return .message_pkcs1v15_SHA1 case "algid:sign:RSA:message-PKCS1v15:SHA224": return .message_pkcs1v15_SHA224 case "algid:sign:RSA:message-PKCS1v15:SHA256": return .message_pkcs1v15_SHA256 case "algid:sign:RSA:message-PKCS1v15:SHA384": return .message_pkcs1v15_SHA384 case "algid:sign:RSA:message-PKCS1v15:SHA512": return .message_pkcs1v15_SHA512 default: return nil } } /// Converts an algorithm string key from our test fixture into an RSA.RSAEncryptionVariant enum case private func encryptionAlgoToVariant(_ algoString: String) -> RSA.RSAEncryptionVariant? { switch algoString { case "algid:encrypt:RSA:raw": return .raw case "algid:encrypt:RSA:PKCS1": return .pksc1v15 default: return nil } } } extension RSATests { static func allTests() -> [(String, (RSATests) -> () throws -> Void)] { let tests = [ ("testSmallRSA", testSmallRSA), ("testRSA1", testRSA1), ("testRSA2", testRSA2), ("testGenerateKeyPair", testGenerateKeyPair), ("testEncryptDecryptRoundTripRandomIntegers", testEncryptDecryptRoundTripRandomIntegers), ("testRSAPKCS1_v15EncryptionManual", testRSAPKCS1_v15EncryptionManual), ("testRSAPKCS1_v15SignatureManual", testRSAPKCS1_v15SignatureManual), ("testRSAPKCS1_v15SignaturesLength", testRSAPKCS1_v15SignaturesLength), ("testRSAKeys", testRSAKeys) ] return tests } } // - MARK: RSA Test Fixtures extension RSATests { /// RSA Test Fixtures /// /// - Note: These fixtures were generated using the `testCreateTestFixture` function in `RSASecKeyTests` file. /// - Note: All values generated are done so via Apple's `Security` framework (we assume they got it right). struct TestFixtures { struct Fixture { let keySize: Int let publicDER: String let privateDER: String let messages: [String: (encryptedMessage: [String: String], signedMessage: [String: String])] } // An example of a 1024 bit RSA Key that's actually only 1023 bits static let RSA_1023 = Fixture( keySize: 1023, publicDER: """ MIGIAoGAWLOVh+J+wTEgOLuM+vWMeBZJTH9M5j9QgwmiC2BaVNeoUyvyw0hm/b9mXPvIP209Ml0F7mm1c4iWZX+7WF/YpML3S682IqY3sNbxg3rZRn36FvEnltiL+ZpUStXPe12p397KkdinrHbdVohNt0gXQQjEN6m26xv99nitPU1XcjECAwEAAQ== """, privateDER: """ MIICWwIBAAKBgFizlYfifsExIDi7jPr1jHgWSUx/TOY/UIMJogtgWlTXqFMr8sNIZv2/Zlz7yD9tPTJdBe5ptXOIlmV/u1hf2KTC90uvNiKmN7DW8YN62UZ9+hbxJ5bYi/maVErVz3tdqd/eypHYp6x23VaITbdIF0EIxDeptusb/fZ4rT1NV3IxAgMBAAECgYAbtkeCQ53sR6fUcavy/+IZ5oSR9LeWu7MwrULGIR03ooTBL1rR7f3XSwP1CuieAEf9QxjGSppY9RRfs49ZZeBuAqDgPmQ9iukya+e3pm5N444WyR65hxyDUuStMPHmwVtUJg+prMOUXEe43PJfusMtISi8BEiNMY9DacLTCJAeTQJBAIgMqq/Ux7HWyQ0tCisZNPQZqGrlkrw4Nzv2DZmLlYEgea967LmnOoYcASAZODAY/yxj3vnfLX3yvGX+CdlesBcCQQCm6CRzikQfRGtYEB92ddV5xeVgN5r8rnNxvD+kBuMB7qrljta3Ir1JHP3gmA/zz39IvfRf6obdd1Qd1Ym07FT3AkAjFlE3A8N0xBYaBdGnh9q2UZ+z4f1T+ZOVLUIYpX0rTjrT3PoMb2qSh8pqgtaQ4QF+a0toWfybjOy1ySy1GMyFAkBWS1ftVON7twg4870QpkPFPggmAxni4t9VQps010qvSRKatYtWDGQJVS/92yEEUZfhqDSdEsi/4F5hPnKAVGBpAkEAgbpGZ3pPOLjtVgGEkF9srvegUinFd4+s1wL9SVdb3aEk/dqGfScVU9JJqAKHTjD6ULX0qfHGZTrKWQJi3hf/IA== """, messages: [ "": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "algid:encrypt:RSA:PKCS1": "GrwJv13cGvyLbX02dNMEuRYPPGiP7xxNi4kqPs/OHRHkHhA+4WmIZ+aYfOMlFdoNELJdNAr5lBrr6pwiEV8WOyp0Fnqql78qKIj8YvqDiK6ATUUxuZmWBQ9LzxavIulWeZg+/VqJSMKE3FEmpKkXWCkAi3SMo5l0fgE3CTe9luY=" ], signedMessage: [ "algid:sign:RSA:raw": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "algid:sign:RSA:digest-PKCS1v15": "C+S8K4B+W3eM/et63v3nwRsh3ATZJ31bDbl8qhnJ9pdF6So85GzeHPQY64yzRfp4oo+JT4W0WZAhNOi6u9NiBbhdXUPzyj/89rTSYmMEi7tiIhlaoDQV8X+a8gVTJqfM44xAaT82DYLP77TBUjDJEG9WIWKLTBx1EytkvtamRpM=", "algid:sign:RSA:digest-PKCS1v15:SHA1": "Pd0odftcQWd47zlDNmfQHZMdxZPpC9gmivXOfNxOxQ31TXU7g5lglVzUMrykz4YViffJtT6v4MC5J3RRk9a9INJHCpM8hHPx8IgtQiNVN2wHOMB16kFKNuy3d9DO4v1Qklg3MCntzGZUB057UNCwLuvKXc7P5ZwCXPt47Q+P3wc=", "algid:sign:RSA:digest-PKCS1v15:SHA224": "J7/kWa5xUBIKdxLSmsOINlrDTlXLr043xbcH62P8mDNHIff0CHDvZOQHU/r0+lAdtlzB5l9jLOLR+hkyQ8reBL6t2jWyfKPUAVKyUJNT7zZfEfFaGtBi3IK4nS1GQKj7JPJ1d0SCWUCTX4SkLn6pESzR65YI3QIJK/GG/nxmHkk=", "algid:sign:RSA:digest-PKCS1v15:SHA256": "FdkW7WKOlEIBkGSZfzBi9gsS0jFy++MDeZXwe4pWgR6S4J54a33Ws3uwQwnOW+D592IEq1QG4h+4pSmuusNk5tQ7w2qCHbbW7sTZgzWVgpF1HfZ8c0xAkd2oWzw2S8/31iDDromo3OLsaa6C+69bhbqsuNwgkvyKuSxyqziZWA8=", "algid:sign:RSA:digest-PKCS1v15:SHA384": "K5PyLy399mIrI3avLx8T2FwIOKYjy/crsN3VH4GZaFprP4q3xdw9a2ldlngnkfThKTphyS3CCfpACO8V7pZB2Haicre04tgd6uqYwMMBKWTHi4VVIzgwS+SN5L/sC3d4Gwoh6Y9xtUyAbB0Do/s30hbFE8bGC9KV5JbnUairRB4=", "algid:sign:RSA:digest-PKCS1v15:SHA512": "H4sU7sS/hFlrklqN86CWg6FHlF9l/Ll61SpS7wF1Te6Kj78tj1MZd7QMlVKEWGM7RLI1/bkqcTcNzoLGqh1zLI1sg+nUzEqJnx6nCyFT8Qy/V55FqC3wLVpICe99SewDnMsAQiWTwVpiIiwY0vqnS4r+FlCi5Rx/midH0HrzJ3Y=", "algid:sign:RSA:message-PKCS1v15:SHA1": "JEKtxjsHSejtvffWGafUqy3SjH2EVC5rmSSpz5v3IfPjIlVJxiiCRr7gDwaFNgfNiS4ZaVWGpw7hMeduP0RbsrLezS3hKtaRPlpIo89ET6QpDEjYnlDAeyVZQjgO9EOvkCCJ10FotsMRYJWoipePnkqHDlV1bf1wVh599iOMNqs=", "algid:sign:RSA:message-PKCS1v15:SHA224": "IvGyNwD8S9eSJ6TyxYv7Y/g2qOvpbcNem68LI1R6IlqBlTFz7xGpdGriLQOUC4AJL/O6NB1AtME4wJVQ3fKCDlSsASy6EGPtIdwXwdijSb5NkiR2AlxcWCBMFuNHlEpM9OrhhaEows4Y1W1k5l0ws4vbYY4/BrwceIeGSLKDux4=", "algid:sign:RSA:message-PKCS1v15:SHA256": "SavoMjikFHGb/7UOFVI6+FCr2igcsM4esTqvBxeFhHumFGc7Y28fJXIZ1gvw5oqYdj2jCL5okjBUVVnkUkY2TvokN7GHAt0KFdv6F83DdLCwMwaGURgfiAxfPw9kDGoDkqhi9bUdC4FTtOLaK6gVrQzIlqUugGBTBFKySwqdqF8=", "algid:sign:RSA:message-PKCS1v15:SHA384": "URo+XyJE9cFziAeXJliysj0eO629grgTUYXRgrEOA3B6uIOyh0CFZPi/pKpJFhjGJrSAARDzfbH5AbftEo/C3OSOYOVYsgT3ictJBlYk6NsplouCd/CnkdECi3NBe7MIrsp9ekZzkfULyNje5Y8tt1d0PfAgHNV0VHASxqVLJtw=", "algid:sign:RSA:message-PKCS1v15:SHA512": "DslGHod+WHWpUFKLrVU6mdJZh7KPE8E7IMPaBMEs6hPYHdp4Yqmv/2jiPBcnqgIfwTX8A5NVtUJ0EQnjVhFDIqYQXP5AplzaD33dP8IEa8ZhIOrBjfqTZs29ApLrSaPxiT3TRP9Z0FMLXCzU8E5QJuQSomLkpaaHIqyMOzyqWTY=" ] ), "👋": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "HXPOd8MFU57jSnCPj+/mAvzfzjOEgZltWxp3Aek/hhfH31t3wgaB8JQ/A502umjrFlnBupMwQaQr9iJOWYKTFClfDx1T+BFUJfnH28I1etk8DeD3lEiPTMuV/caR3bT0cxDA2TKeMpp4BSOX7iiC9Vd3WaOMH3xbH5UYFUbEdHg=", "algid:encrypt:RSA:PKCS1": "Pi3h0pakf0/QanjJ0mM+AExhqPYnGFX6Z/fji7z8cX1gD8eIUyk26u4opDjyVPb82JOY+ulRBAUlBawcd1M2aiY3O8Bhzpn2awEy9Ps6HWUa9Yp4Un3hLEmySyajb8QdUko0OWzG28cEoInGiOgoU7ko3excvcbHG7O0aJG3FDg=" ], signedMessage: [ "algid:sign:RSA:raw": "TbQzWXDIIX3vir2A8YPSxBLJsIqc1EfydyhTcwSOvHPtKbkIS10bCbtrN3tcK8W/7Ii1VluZbQmf8rQjUXgVAF9s7LNoDmtrHp3kOBUwSBT5ebbr/OIskwVdt2IHoNyYtOFlx8V86LJc6HSLYAfQplEBQfVd83D8EjK6DHJJRWE=", "algid:sign:RSA:digest-PKCS1v15": "KJNf91GcrEFS6DZrRhqs2WlVJrJl2Rxmuf7OaPT+ymTDyUGMvGsfM3MGlousZAk0Z4HvaoJCKAj/cc2UecKTM0tf0q4RaO12/qSDM242Max5MotBVVY/LihV0Vv5FGLX4AvHkDCC9W9nC/jDSGMfGSzLqbCI/J4ljxcFrJ6zWeI=", "algid:sign:RSA:digest-PKCS1v15:SHA1": "Bfn8f0RrkdJynMUp8dHWzpAqGPxuI5dKySwoXOmXHtGcqypvv6mnBwzURwIXq6dRA5wL8/GcQ6GAUkPLyQ7mbpnjKZEf0/nHfYkgNkihV2Ay/VtQmvpwwnrtlDWmd6s/a3eLACYZqiNOmNQan2jPTNCbQZZ1idP6ilv2GedO4Qw=", "algid:sign:RSA:digest-PKCS1v15:SHA224": "SZN1dw+SCGZUI5Ue6x2rK6giO9JdTJozEkHXu2DsE1d51iVOHD5eo1PXAgmFRpkfV9DTzEckFViVP3G0BE5H3ZPsem+HyB6+nPuAVArqL7T0JBUzHgZ4T+vThfvMJzExcDISLK7gwc9NOTwIKjePWBoeTv9u+CPHVkxFm2uF+lM=", "algid:sign:RSA:digest-PKCS1v15:SHA256": "RghR0cKvs4hWc4XS++IPdAC8K7fri54d8fxeOoWXMPejVh2AZy9dOxKJm7+NBMJxymVODrxa8JbzKmJ4h6agMtCwH2B0f/NJO67FJFbn+RGsxG7MfvVO4z2Ejy+IOQJEOkIRTKxvwtRlUiJBgiQfdmUClPzd7j6Og8fGMumWFSI=", "algid:sign:RSA:digest-PKCS1v15:SHA384": "RUgGeY9N6zWP9AfU3gLz8oiZaoyH5fvKCULX6/HuqDvSa2Y06hayCo7JLoCLDuLVxMvg44DobR7z6j1Ur7v85Wqv5kPTAAIiGNKEnt90Hpqn9f2RzrTToH6fnQC7ZJ9+e5N72p57fqIjZHlEnFk7o3XuEqpivOKZiSCEwo4KDS8=", "algid:sign:RSA:digest-PKCS1v15:SHA512": "E9V2lyhaDyGWFnCKROi3kcPr8QG2AfCYSSa9tyj8mRFUmjnNyghpUW5gPDCy6nACaUnPOxvB0trJUD+irvvYD+7jr+VDnxCeHwe2ZE/ize0vvJFvtLSIAGGUA2aXTU5CohNvNnJs1wYSIWYVrWkaU0yyA8H73kKzsAcAY1+KSnM=", "algid:sign:RSA:message-PKCS1v15:SHA1": "JMui6+GXCll9KJ+G0n3XMv5Sdz0PUQY6hDMlrygCdtFiNgPWfOTko/Q88RVHFJXCw7NHxyae6G+IPzvve2AQOEP7TdrivACM3C7sqchTWKEnGV1DbZ9r0f2EZjQ7VPM90mnmxG2uDPyrXTKUyVvTTH/SlYW+Zt5NO5TNf6KH2GY=", "algid:sign:RSA:message-PKCS1v15:SHA224": "VIP9zszWW0M9IvkCeMaNrgd37kfDI/fKOfSCeK40XvcTYyFuNlSdYhaLzxxK9UHcpD5nQR3UPUMym15FQZb6XvDb3ru5f4/BmeCmMdn3J79izPIZAH5JvyY7o6AjqnW/1SjbIn/0sCVuw815hublKifT6A/kxT21y1KxgUtKAhM=", "algid:sign:RSA:message-PKCS1v15:SHA256": "KE1l25Ld+OvGwxDcww7PUPXWhHszt55YZfSA2jG0x5MCwkQvxkVvUIb3b/fxXH73FJ6stKO7WR47ihnZXzjOv7si/AnxwS/j4r2yHC5bTPz01NqMHbNZ0eAIzyiAl3Lo41njLn/QdopFORE88S+G5OUgCaA0MfmRyncOrC+Qy6E=", "algid:sign:RSA:message-PKCS1v15:SHA384": "NP9G1fQikdVJNqxxsLetyAEEIgiZ0AkOWSulSW3Azrz3koW7YLoDcucP/dj7oBtRNmpQ2YD5J7JLY4Ty0BdxVt5nekBVTgrp9kuChqDKAJALnU1CtpWQIDRzeX7uoEytnjdo2No35v0EaFdy7h6i7c2ipMMB04eSz67X2MsD7Ro=", "algid:sign:RSA:message-PKCS1v15:SHA512": "B3ZgVLml8rkRPyYFbIjZ2ZL4+4/qkGzoHrlOCofM569XLzkoImKSYJ4viCFCRJxMBBg/hxBRLM3sSvOlCXAXdICHegyeJ6glS6bD3lzd5LWXIeGTywLd66tR263D5gFjR1Z8HIPBeZdSlDdLDHTFVa3uclyhIy6zHq/OxN/LMPw=" ] ), "RSA Keys": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "Dwu3Aq+tmYoXh2k9RzP30jU0Q9BgzLHVsJfiuGIi34BG5wqBr5Zow8FS+6IGuTdeS5jXBi5EAY7VbmqfW2/L5oMNQ+C+SYqgaVDBXe9a6xT5f7irgkpm0wa/logz3ybEiH7eqs3VfZgwV688PYUr++aHqrti72gd/nmLWLaHvIw=", "algid:encrypt:RSA:PKCS1": "HY9udxFzq4HnQsThVd+WvJjveDONZ7IYZCBAD7IFDT5o1fTNrGFKtFXfk2P76ha1tz5P2mKHVkDjaPDd1M6x+RvmX9QMMfrYb3sbu5J+/K1+vZ8bSwYgO1ou/IW0T0KhZ7lkuCjZ2GIm+F5YNjlE0CXox5a+DhINF5RJeqD79W8=" ], signedMessage: [ "algid:sign:RSA:raw": "ItiEkbOcx9MPot85FYOFGyxLA/dyb4Dpf4sv/rFBeCaxSJKIN5JSMMQ5DKy2KKVlQY+Xp99TgInXPu05KalKck3LWjLggdR0b0t0XvEfep8rLzlHkFoaQaVK4y/JDdwVYUoZQ2GYUGCBB1TS0UCfXt1H6HIjy/R/7zVcPpNEanA=", "algid:sign:RSA:digest-PKCS1v15": "LSy4h1tf7CtIZt3YusIwYMgciuRdmsMXZfi3TMwS07xMJWiGH3MAqLjSpoxJxn43hnzqXmIfvUOc6ps1hwoBF2zJKVP6VQUiup01T3uQiH6gjg1kkIzrsAmUhwGHMRkgpjvQgb4PcqUXFV6j5B00rUlMZq5IrJxeFIwdsNep7TE=", "algid:sign:RSA:digest-PKCS1v15:SHA1": "I1+a/1zhnmBWOVkoHeRzKb5a/J6xJN3NhnZLduUStMgS/Nm0SV7kEgalYJbVGMIh/kXDQ8BY5lXuWrfOjjisgmSOo5NxRfOBcXxwpmRKstGi7/lDAs1LryCBWajv2hyPSEAky3nih4+8xEhUrjAoWd4shSd7FonUAU027d/AaHI=", "algid:sign:RSA:digest-PKCS1v15:SHA224": "T8JXiB0JlDUC3K8f7NF/h4t9lpc+QPFUUf2AW1nk/bMb1dbquLe2O8AD8Ylfu39g+ebA3W4w/2hn+tkQuVQGMFkZbhrKUUdx/FVVZJveIYigTHjSavM4zJfkdCyiu45SOaY+x7D1WeJHsTbYLSc29qfVZaac9LYCHan4oShnIBY=", "algid:sign:RSA:digest-PKCS1v15:SHA256": "F1rCz2wqbs2JCBEAr4J6xyX5d/xeXaGbL8G00dpn5Zz7i0a7n7avBdTHTdnvCtxaRa2bQtxSsQ1KsOZT3BrVJCKrtcVYIf6t4OKP9tpjh2BwT/AA5Urvw2DDDqMtlwZdBEJxGYLumbnHxUWrKfBzSHMTK2vbwJ19IY769eLfvCA=", "algid:sign:RSA:digest-PKCS1v15:SHA384": "LPRFTu1T5BxGUp3gLbsR70sANSnY67f6vhGvRIU23KE7dUVlHWkm0rTeZNif+LvNWL1suxBHI6fJPLkHfLRd/CJlBOIOzOvvifu4kEX3VIySybp4/fEdBXlJnpVzTdVzHh2hifkWme+derDBJRcXGVO6IcHpJl0xhXxDaTUfMes=", "algid:sign:RSA:digest-PKCS1v15:SHA512": "FQToDphnuXKEDLtEJU0CSf7DgCivkzJLbNnmxI+jVajklROaM+h/+oQcDPDohDbjZ6fsici/rByLrkjgCAcHYTJ1cRzsGG/QIbXGLwjebl5nBD3NiC50Yu800idYmX3BhMEaYhB7Ce6xukJ82/DmCIq2fdyV/usvUJFU7pnRziA=", "algid:sign:RSA:message-PKCS1v15:SHA1": "UQ73vHah5CXieEVXBmg1SdcVOfO+nj8VyLH8m0b30JCFry9MztxJot5BZZHNGzMbvDHoNRA8ekMgj6bRwrHpr/VwuypJ4IbM8n5C3rWdJSoTfBBPWZeywJkgeo0LzTVTlxjBsCHJQiIBsfIwinQMGARfV/yJMo0Xfk4C32avkP4=", "algid:sign:RSA:message-PKCS1v15:SHA224": "KU2uKP0Y21I6xQZrIOmSvZZJE/YlU1sNis/y0szbqbF6T9gFSlnrT7RIuzfm26uWMH+d9jCuq6wRRMoNolEhLJqUPzq2xuR5OwSm++U6o+d9OW1AqWjkwBqVYeZKa6WmmXKAo4Y+sLPR2iH7oqUTU1Jfzkn/3u16nTYK7WkLJUQ=", "algid:sign:RSA:message-PKCS1v15:SHA256": "F8Sdbd9MXz/nigx+honEk/anKLyuafO0H2+fNmkG9Rb3V9cyh/Iqyo4kN7YGXWYHpzH/JSHiUNOFOlVxsA8vQNqFt+V08z4XSaHsFMmN9gjJBDyMTwMibSxqzJPwqV6cWjzVYj/78RdOt22z7Gst5Vrc0sJIob7Lvz9Q5UteAcs=", "algid:sign:RSA:message-PKCS1v15:SHA384": "B44iwunbuMkEubxni5MM+T40O9/QoY16ykiWIUW5efwpa9WGbEWBVTb10Se4J0qVh0w6J+FG+xt2qaB7DDr2IInbrB5SIKpIngZtNqqE0n0AaD675N9d4nTonf5wWVXvooKOWJf4zaX4qtAvZYKoZs9JiBVbmPXNLvs013/+QVw=", "algid:sign:RSA:message-PKCS1v15:SHA512": "PndOMnWTZ60cGTDbIwgfHtzl+6Nmhu2Ec7KPvRtPnV0UhI2Yoxa7dFLz6NQUMUkf0p1cDFEWYwAhdQrIzUROoTr3p9dCEoxf2eOFV4S3aEdFGDy2nh0WpyQ68PFizAgSTJpT6ePF8u/1d2npPpl2P0fcsdU3MlOwaUVyxkF3ngk=" ] ), "CryptoSwift RSA Keys!": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "ALMTIQ68Jm/8xrjuQE/b0USTShPr1sCX51EVRyheG5gKr8HqZ3BUWADdpB3M5D33A0QCkKqp5NMs3qNvUaGspHTAUnV6BvWuX15kk45P/ibw22n64SP8Y2CU/tGCc6Rf9B5DJ7OsL5n7pZKAbF2sKlPx8VEyFbwXyUPT4cao6bY=", "algid:encrypt:RSA:PKCS1": "Tav12GnF3OKhnAkZgSa1Nso24C/+qwXlXuA8BcXybdWAyr9D7B5ACn/qfYyoDOvUQSnDF8xCPrUTsxaZ8HaKb0u+620QA57ueQdQLSK0MEFmwdOIQaPGKm3KwyIXx6APkeij+RA4yNjmzIgQgKQoQsmoBOa01mMr5teFnVO7c1s=" ], signedMessage: [ "algid:sign:RSA:raw": "EIu3l9qt9AyHoTSE5oHM4wICOrY5QrGJkLsbwewA0SfwRFEhmwgBD2tbQ0tK6o8Fe5omkPwoh8fOFCPInTD4r9D3bU3mFSFnaEGkDZAQnVL+0WpKUnMJggDBoBY7Fz7PwqTKVFGPw2ixfK4IoHB6t0qfz3Q0eTO5xzRRtj9XZ98=", "algid:sign:RSA:digest-PKCS1v15": "IRFLtTvPhnF/tC7gYCKrhmC0xz9gYRXsBnJtg7yRjv8mRYCDM+xugVDW2GBSRdQRssQBTcXg6mYV6oSR+nlqU4vkf37BVbHSrIfSGWFOZCqkGioMaswjtIEUR10ia9s5YDH5fVk3vsVXJw9s730jAYW8B1T8PIvMAj1Xkzr775U=", "algid:sign:RSA:digest-PKCS1v15:SHA1": "", "algid:sign:RSA:digest-PKCS1v15:SHA224": "DQtXIwKJHPnR7vG+y10hrnAt/C/g5lMoo7pX6Fqeick9mfGU4tCY4/COUdSUOOZYLacA2IhYAbgfNW1P5GRB3zELc3mveHwIVlovyY1FOhEwzbp+S6SRWP9dmBjGlswpmDvvQ7RUrykQabiPYnuqYdR1jhDbdWx4r25vF+fGhn4=", "algid:sign:RSA:digest-PKCS1v15:SHA256": "VeWhPR0yNYwr9ARUgNEdB7nWtYE1ItUTPupPT/1GEkGD4JNTi0wZxcuIN/Day2QhbFxZ/jDR1L6ToX+mcfT2pcpxAIfJsJQmmj5ISvbrp4zr0Q/vnIwv75BqL2geMx34raQOD5If7HNEYJrHBmQFwq4aKih+e5ADdV0Re9hC7Ds=", "algid:sign:RSA:digest-PKCS1v15:SHA384": "C6cOQd0Z5F20L+ZV+r6WdElB05WRBSqh+lFgR9yDt/kAR/5FRNaJ9ZG00+0NiVZRQ4fj4SV+SBrmPzBfk5TYJN8BQW1QPc1GFj798/aem7qYQySAv1Dd2v1CRhAg/nW+UbK3YfE/68P5MsaSX52dhJfV1+DHVufZytdmHlOgcao=", "algid:sign:RSA:digest-PKCS1v15:SHA512": "URJmACamzelP7FmEIZ4nkymu/jF67VBByot5sscDVUGCQdwDntegCqBPrXJFb0bbT+55dmRCo9E402mMRTLEF4y+Gbf+yFpKiPxkHx8jGbs2CwrFUhlKCSOALV9gGz/QkgEm0vWyLNu7a0TL/fEipkHKURE4dcR0AZhj+1UCiYE=", "algid:sign:RSA:message-PKCS1v15:SHA1": "B0hA+iRuN8sVDLYPn2365eCuk5qv/TbfXhqwk4HKHWHDHDu4/f+lSX9AS3//ZfWiJQX1Kz8y6QJbSmafr1LgOxDDLS9VpI4uuLYPcW8HLf54euzHADF5Kh69VAUeEq4f+8yF2su9mut5x9561dRa8iG+5+rIIAJ48RLjAzzV2Lk=", "algid:sign:RSA:message-PKCS1v15:SHA224": "F1B6DPF65vdORuS1mTBRNUW7FkF0pA3iMaU/VTWRomKRG9ztomelprDptADWLbZY6DRMQXSHfZM2wXBLPZGSlF8K3HdDB2xEe5VzZtLyzmY3K118W7jXU2JQ7TUG78aCPFDi76/IOSQV7jwLmMy4/akYILnDVxStIydMzw7uZlA=", "algid:sign:RSA:message-PKCS1v15:SHA256": "E0SQoSKJj1AMlyz9oy5uETbNhnfVqIogvtugXOmD+KouX8KsHZpJBUj9+MSJb2vWuDjF5qGsSaDGHHkOIEZROCxHyStYIOCtofPMIftov/yXJXTFhNcouYgQk9DD8yzeFII0+rf73or7Q4C4SzlPXF3Ds9kut+7Ozw28o1iwT+A=", "algid:sign:RSA:message-PKCS1v15:SHA384": "Fe9Hbg5FhjN9subc+TRovHrq5DHncrZRkSswqy6rVNgoBKPuxQsbEP+QgHZqg3zgTA6mo6R+icMvDYcUQY8X5F0pcx/KqSTCU2n0Ec3VrxtngxXoe96ra04aEfwToIWybFslC8Bhr07fg24PlZEwFNCGm4cVEaQNQD+GeKEiiJs=", "algid:sign:RSA:message-PKCS1v15:SHA512": "S7GstJ9uVW5I1NIgMeF2n6JA+PpGLXFJmLTAqjpnyAK+et+YIRoRA/bYTftnXxMU0wsUansUXxXOs5nBrGf+rdtLLTgzIrt4uHsUB05Cl3sTBVt7p9tK8N2fxpw/4F6Syn9zvxfjBJzKdMYrZw3BtsRHzXO7SfqfayRA8oQfk3I=" ] ), "CryptoSwift RSA Keys are really cool! They support encrypting / decrypting messages, signing and verifying signed messages, and importing and exporting encrypted keys for use between sessions 🔐": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "", "algid:encrypt:RSA:PKCS1": "" ], signedMessage: [ "algid:sign:RSA:raw": "", "algid:sign:RSA:digest-PKCS1v15": "", "algid:sign:RSA:digest-PKCS1v15:SHA1": "", "algid:sign:RSA:digest-PKCS1v15:SHA224": "", "algid:sign:RSA:digest-PKCS1v15:SHA256": "", "algid:sign:RSA:digest-PKCS1v15:SHA384": "", "algid:sign:RSA:digest-PKCS1v15:SHA512": "", "algid:sign:RSA:message-PKCS1v15:SHA1": "G5neBQbE/ctrRD7Yr2DIWDSxd39WJkKnym6dEkyFq6pQRsipNdGTCmwnjXXRXcWM6XUJG4htvaEnz+5W8rZzZ3fiMuZgRxlA5FpbRoEwvnArYovxgQFiazgRi0CGu1nUpbfgwkuSTBxERWUc+l4jImcWeqY0YdFEXDcADqp1gmI=", "algid:sign:RSA:message-PKCS1v15:SHA224": "JlmRNo9gevd5XxX8FsnZKSjHeZNxIkPHzKnSMBhFjm15Y6QBtcStIkAjg0wbmcxqX5NX9DAE29t9+4dluK6HXvi87TBBrsrXtMzm1EB247+9224eu2y6kghFuPW5lJFITIUdmxyKT/14zR29OIfEdCpnS9zjmZ2TdOXs7bZlJbg=", "algid:sign:RSA:message-PKCS1v15:SHA256": "Bn06v122hbYHG9Q8egUW7RGV4cDK7jf9EKJXe4ydpjhNs8pKLIhPhnS9ax9wG9IJWR+P8n7xwGxfFNdSmcrWIfSbbYat5/jaO5718voNC7+bq/N5g2mzzz4ugRAFXiDbFlA5pWBaAZTE+XwxH0pSg/5giC4RFi2qN28ihvWHyOY=", "algid:sign:RSA:message-PKCS1v15:SHA384": "NvxOxIy/szgB5p+CY02JqM6ZwJLvCTLYOpn4xkpBO/kxXG9NJX9AheD8T7mwEiMQw8dyQ200oZFkyUDFjBoHNZy8rXRf214INpryypjobte9oUCju70v3g6Z/AMkSetJqBi8hxVpm62op0Co2j91pxUYXvO/XVpvdB/6dY2akO8=", "algid:sign:RSA:message-PKCS1v15:SHA512": "K4vWQj11zTxyMsZG4XKYrMqdxYZ7XxRBNBREeYYlL5xGOnRdmW+m5ZPh0h+vRIa/8IEPoyd2fvCBOUtx1euNQfPD1YT1UzxEr5ua3cQdylCWa8ghfCaOeJuhhMUFAqhjHQfK1NBtEH0bAvvw1XcxLRbTwupdPJjAFGUfmMjfMZw=" ] ) ] ) static let RSA_1024 = Fixture( keySize: 1024, publicDER: """ MIGJAoGBANafJnOmd7j9o05NFzmoOaPJ5tvKMOybyNQuTdElOI0UeUu9FFAKBJD1ClT1WMuyDzIEZMF3TJwohNnkY7q8tnuTHdO/f3Il3b/1bt4QGavVwnrLbalaJgFmnvaLqTs8dYu3nhcUZhWI+eKjTZxjUg1LrGJVbGZtbjTGPvKcvjOfAgMBAAE= """, privateDER: """ MIICXAIBAAKBgQDWnyZzpne4/aNOTRc5qDmjyebbyjDsm8jULk3RJTiNFHlLvRRQCgSQ9QpU9VjLsg8yBGTBd0ycKITZ5GO6vLZ7kx3Tv39yJd2/9W7eEBmr1cJ6y22pWiYBZp72i6k7PHWLt54XFGYViPnio02cY1INS6xiVWxmbW40xj7ynL4znwIDAQABAoGAGexnTJjS5TldvFt7bq9vJuWASRQHDM1UWKyvIZAJYKEUdZ2FEpXjL08pzFFGRHRheX0mXmf2jPYn9dmsYiXhNJsiUH3hV1trsccv4tHG3Ctvq3xJ3BY7K0IGPhGNEAlqTLOqM3QeU55PDUenR8C8Vx4Ooc/lm+YRlZ3w79yX06ECQQD+tDVHmJ6655sipCsJMgOKu9o6Qj4v9FwgJf8InUFLbOqZKAvfAUANBiX8FOKZ/DENAFnU2sQUfB+emoLNEzYNAkEA17a6iGZ2YnRb1jsL+MAj4qOS2z+WG9v2WCVl/ZPATAa/+Np0TUSAu+XorUiG0Zx+pClitmaQgaVBBcwXaPexWwJAOU4gQqiC5fhf/g5DpID9LQSQ19S5mx52b8E8vRpsa2To72aELTthxsxgVXP5e72y54LxsyM5RIacspl+3lb5LQJAQEQjXKHSIVDzT2b2ER0FU+9RwFo4WYJ16RrzQNH1F3FnXjePMLn49IHxiTazW92Y6UWfMCJsaQOX1KdSTiaFQwJBANra8gEZ/e3gN39+Cu4eFyFm8afBd4ffLnpdKiK1yPebsLbTv66pwwCAchv6uyIHihyD6Kyq7XZvhaLMo7xwfck= """, messages: [ "": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "algid:encrypt:RSA:PKCS1": "" ], signedMessage: [ "algid:sign:RSA:raw": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "algid:sign:RSA:digest-PKCS1v15": "yAeKf1vJjQ/1uVxOZB7sCPs5cbN5CTfXkhqFZeFJgahjBgmb+hs0GmIdRjmlgTWAI6rH1Ew56SkiJgkzL/7RbqWvUuqPsyPz97NeDbXXSI+NTy/7W0KaInF3YdR3GSNAIMHy8qFLiCeXNFY+6ixuwFeHCOQrTijlBqtZB2g3+e0=", "algid:sign:RSA:digest-PKCS1v15:SHA1": "dsQr0HbJ5rl/fPLmVPLgyTqk58T0mU7C2gyrt7qni+AFsvdLNY0gIyLKC9hV22ChfFb9FHDSZ0TAnfJV4F+OklAYaGYhAtYNHcdohGN5NkA0P7MN88AoU3TWculwIFdtmSgewZZxED9aaddo9bbUreecaPvzfrJkdpC3qQY+3QQ=", "algid:sign:RSA:digest-PKCS1v15:SHA224": "GMGv/t14qzu7Hl9JuCDCPwJIs9NGSI3ObVHucfT1VD6nvfl01oSmUx5Z8YFG4xh+eTfX1yFwuqo8h8Q56v0Mesy7h0ZBR4KbvITir5umbnxOdVx4CSUG4GBgfd5n+xzC8mhMkfFbzgZa+dDe85XQAfAIY0OBwRb1SMkRV529TWM=", "algid:sign:RSA:digest-PKCS1v15:SHA256": "mbsLcVYBBPlvcpSxdOpgoxla4N1bvN9LYuFvsKiNV2vFZQkv9aFeGDTwesz0Wh6FTzObuu63veZfCAKS+WYkEXBmoAJ+ZqAmYhBDEtuFPUyP7X0xK6ZRL8x1CB5qEN93k1eYRe6c4lNwTK1wxMIr7ocfBlIwUjANK2ZLlvInDMQ=", "algid:sign:RSA:digest-PKCS1v15:SHA384": "RxSKRd/lot+Ba889hCuTwjBUt81jiGmAf+0MFttzum/fBcyhy419n++mzPzVG1CIZtcBS5sXdd1gqJNlve+E/GG0f1/vuLWuursM7+IqWntukWk+v6zmmZq2S+skuKsYZJfDTkOpzfYyyARqWWL9fweut3nwPRSjOvl5q+kgZwI=", "algid:sign:RSA:digest-PKCS1v15:SHA512": "h1n6982vnm9JwiLFOsLLlBmnEw6RmlR8l+XjQPUyUaTwBaXf6jpAORfNWarWcTR1ZG4DQVvfN2lFyP9mkMwczXkV7kKl3kDMxqZ6DrFL7GLmDKh/xRvglNhK/DxfOV+6PmMhzHLa01Mz424B0IX1uE+nN+XknGwPAQ+qIKKOJqc=", "algid:sign:RSA:message-PKCS1v15:SHA1": "A30eJ8+4ldu7KRjdWy6hvaXaP3HqaR7vq+/k+wm38PbjAI3YkXZQniOm+q6JVkYSfy7EqpnMvU5xiC5gkYSser579mE90ZwJd2nNO34DzEZYm/rAZaEYB/EeyIDH0l8mrAy5BTG93HSa8EbX1hvpJ6X/LfalwJWI5/eoxFczrYg=", "algid:sign:RSA:message-PKCS1v15:SHA224": "JQ48KbGEzM57dvsBF4QLJ9hP+U9fJPZTSonnls55viRTuWToupY93vGfcZPRL0LoS97Twfxt+Ax13k8Inu9kJJyjPinYE3qgdifUTlTUtZJmSfKUD8L+/B+fVbeJ33znSxepBOu3zevOSVIuDjXlIRrhs52oGtK6/7N7D12pXsQ=", "algid:sign:RSA:message-PKCS1v15:SHA256": "ZlSnyMd7IuUE3+9GrnxhCZvUC6xaWimK8TCRh941xq+Ae6Ofv3bNc8p9IZBn+mM68Q9TX7PMjniHTK7CIoXvLWQx4e+nOPZXB+m9NX63yKxmXtC/yMRo2F+FG/ywYU6J0TLuOov58ULqoIIroUDd+aZZqPnIC0qI8i6/E/DiExw=", "algid:sign:RSA:message-PKCS1v15:SHA384": "yFltWqqP+amkWRgsc0IMvDYC8uLiM6E1UydMdwtnuMidWZxBSBu9M96YcGRKTog1jcWNcTQb0Ly8uyDHLQO/sCBSR2H1vGKd4wl1n6xlBYKQZOI0b1VQ8c1JKHUpSkquVDTOHPhdpzTMD9P1F3AcGEF82BCSwxdNDv4Asag2JnI=", "algid:sign:RSA:message-PKCS1v15:SHA512": "Zv6PL+K65f4MCWdq6uVpfiUh8U02aqoq8uUPSFJiwE+a9SEGRa6FC+Vk7dthMVi8r55JCvXLbMAzd97kw7OXlS6cs42hi2tzoUtewflbdTQyWj5M9ruD/fQtdi6bSXXHbbZEnSwkSfhuGT5DT7ysKc/GAnrIkP8Z+Spzp+CUXew=" ] ), "👋": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "JpNi0ZtVYGFOqzMm0jQm5xLct3JDlizrFOoaOlbBOsLogq3NvkwTS6eiqI39ldbFomTkQeQ5DUXGGQacajzgdi/jPpEs/17poRI5v8xwYytDzsLrF/vjRfdPSbTTsO7WEsFHGcUUrUKt+1jtM0vLBc8aCkkElkIs8TdmddG6jrI=", "algid:encrypt:RSA:PKCS1": "ALOEqjLmjgezAhWo1EsKY0c4rczVDeANjrLp3KAMBiXMkbgV2B3nXttY4qtb/B5nYa2iK1G6XJ+72Yi/9lSJoIaOUZ2JfmhxNGnagXzW9d+NAnt2VIxlUMdInve4gH0P+bKUXtJ4Y8yIx5S0cDgDEaNJA8pGYnFFu/2+ZVfg12w=" ], signedMessage: [ "algid:sign:RSA:raw": "N8EyiZfzRGF2Jh9hFCaeo1y8wGH8L7YB8hscLL1vMwU12hMYH4+uJ6po+hwHDjsZj/nELO+faTX5i0iZIaAWhjAxvW8XEKr3aY5+lySYnt/NlTVwlooMi4pCiKW/VgN0jecf7iumUATC2z2VFkZ4CoL3i8aJx2KtPCHcSGJRxWs=", "algid:sign:RSA:digest-PKCS1v15": "AWWAt/oKiEUA/NkHDb2fw2EN+NOYNXlxa6lh7oUfREJTOLHBLCORBFo5f/BjTcDdJDYJBw2Uw4mWBWphBoLgmD06DsjmXpn8WxMIBKkT10qJNJAooPxDf3YG8e3PBirEh90N/zRdIhPNsbWfHVMrU8DHzTBwk2cOYgcPu2Id56A=", "algid:sign:RSA:digest-PKCS1v15:SHA1": "Baf6LsSUSMFs0FdIQXPe2rRRch9FGsOtZ9WSfzq9g5NMjCAkObQGCtlMMVRw5L8qEoz3UvKJ1OJ02TTkpk27VTuS74RL2GzyeF9GfvQSlVmHW8gDOUB+0+kPiU2ZT/cwG9l4MTWkvU593cc7J9LXZho/fWhHffP9TGdnCtIZXRw=", "algid:sign:RSA:digest-PKCS1v15:SHA224": "nL1mwFUbINKqYdKejLf/f3JhTfr4FPouVHDOXfN6CyKkQQg8DOE1ACERQEGIDmYyetSNKEEgqWSwN+u46Wr7SXHacLcCsEtQrNrisdwZmv7BCsMGzjXti91JHBLqZHTY66v4Ht16w0VxmFcBmEW+2AlaK5jTh/YS3npiSQ9NX1E=", "algid:sign:RSA:digest-PKCS1v15:SHA256": "Jb2v8DU0T+4Qp+PF4V4T404asAiR9s1XrBDehLXTrZas5TjRY5hgkc77A/a+lSxhRhCDA9Tc+Nw0ACMJW2PAYtDuNzEjxv7WkOhTJ+OLu/eWFIo6/WFRnPRu9a0uZzHEP8T9EPrhasoh3R5wQPtxlB2uBn5bUHhYEn+qN1Y0sRM=", "algid:sign:RSA:digest-PKCS1v15:SHA384": "mxy9mxRXZeDHZa2TLMtHMt3WWhEyCHBhzPDILFr4AJ9X1RooP8WLocn/E2S2LQwYLYpW30ZOaXZY49Zd4dp+1mll9DppXcJkDWymXqdRj/T29SaJTDAIcGDfP+wnLjoOSlXGXs5NvTIJkgxeL44lSPoAvJV4vhNpeJGyp9GU1Ek=", "algid:sign:RSA:digest-PKCS1v15:SHA512": "iR7KaI3RtGeNN1sSRmVxcCGb2ElZMh1dq+pmjg8igTicGpDQ//toLeyGQTdydJzsPFdYBG3SY9AIdaTOiZK6btPP8cL+tq4aRQVMy3aP53puahdqgi+ODvK+O8WQxSLwg+pDACMUCkIQJQA1nWoQ1JIIVq3ExRFsP9H7i2770QM=", "algid:sign:RSA:message-PKCS1v15:SHA1": "fuBRRx3U3JViImQMfKv1dDNoKJPtXqw6TN/44d7g6kWqwyoXe6XFjpy0P4tP28YAYJzCa3mLMfXTP42+B0tYXZA8bsWifXK2BsWATMiLRCikkyftg371eh5M/+Fw4oMPf+YdbeZmLgOUkdBR3avOjWBC7AfjgOKdBqkT6kVURpc=", "algid:sign:RSA:message-PKCS1v15:SHA224": "0qI2qFArOlA6uRmNF3uguPdmXhIBqhxZWzdUeXAwBseQLBPdl7rbsrh/AgwXFsbpvp3F4K1l1y8tON1TCUXAcYrP0NnCYKYk3hUuzykqWhhAX0g76+X63mPg4S34YQZfdW8EjhqoE7oubD3OslrwPdBR8JlwAau9f6CwbK7YkbI=", "algid:sign:RSA:message-PKCS1v15:SHA256": "noHkDUs5ZO14CLy95DEkOYQG32YmaruzMIZgBYgwv3vi2LmYmvCuOt1DoSFRb+nV/uIUrjqgAZFav2LBpwSuoHsB4sCSPWWIQicaln/EJx1+LUXpF+gG0KZVOkJNbvUTi3QqcXuW01TZZmw8MydKN/QTlBWlYhM+sm+1w0gYwyQ=", "algid:sign:RSA:message-PKCS1v15:SHA384": "Su85Fjt06dIRdIEpufLFEBDVumsQ8EuWyLlH/qEnHyYFfQP/Q5TylxgBCc2a+nvuX74EsvUyT65zIYrHn48zKKdLz49CClGqJlMRIjZbvyrAT3+ksK6dD+tjy2fEgtRDDcwLICowmF/UuT4K42GcYGLXNkZju8Yulh4EJJL/mi4=", "algid:sign:RSA:message-PKCS1v15:SHA512": "hSgRsvhQeZJzf9ggO3YAokfrY8VsL0q4OcZN6msqKXZE6u0Q1BMACc3P/BM3SOSOEYrYLr+uedpntEvXPtiBis4R5VvamMQF1tzs3QMPCCcbnwMPtuJoT44pz44NYdHfAyI1KFgZeEwcOevJW/DrUFkQG8syR6ew8mE2sEJl9ws=" ] ), "RSA Keys": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "A3vPcAHp9sIZyBSoSJ9e+5gF1I1owZtPn/T7qYlvkEu7jCELW/e4IlLrHh8oYZtaw/+NJ4O03CoAM5ve6iXzJlCWvoaEBeAVhnJZNEwArmKk1Ap5R0ZKty8RiE/V+3hhKqSnz4yxgvkQpjZN+xNKWSUba6D5n7GkrVykdzHY0sQ=", "algid:encrypt:RSA:PKCS1": "ottU4RoCisIoZ1zSjM0Wy3Xk9HIzFBiFzEcNPUqcEgd0FY7KYDnnquXmANqj/a2cAgVFqZLWrYgehvOm3fpW0qdNHFDAKMQEyCu0qp2ovYbkAmAYYs0klBsNRIQS6QICIJ3sXgCi05O/0Eh48k/+fa0VDqrBkAlBhLQvxvZF0j4=" ], signedMessage: [ "algid:sign:RSA:raw": "WenkBunlIy7kQ9BxuS/fG36eHLME16vGTuuF8ZMiO3RXnJgjS0dnMlDSBAcGYxWqDq1cZU+BmYUjz7Kzk/WwS9+DimrFYGyQjYfDLylHVZ3HN1fJd7SMgmG0LbonqqKBLm6YSls2HC2Y2kApDnfomc/owevOEswGaKYybI1ItK0=", "algid:sign:RSA:digest-PKCS1v15": "APEjD2A4ULLM8pf4QkifrhmW3WmrwWtfbybmCSdPlu9NQsWt8i4MbzSqF752iDhafRQHZJ3HRh1COFnmBGmt/OHbJ14AMRgiL0MAPF5nwDfZGhkqBt/DsD1K8i7vuSZCS4sLLn5SvcvdSYdwyz+cJTRkis5wKTdwbENF+pKKSgQ=", "algid:sign:RSA:digest-PKCS1v15:SHA1": "x7WcrpJivdUX0MeQn5btGtWzqvg7vKhh0aqr0AhXTm/6R8jUsvy57nKrWYT3oZhRaZYQiM4iSOrhRvgXzmd/3gFQZtMCK7p1CAh6Mebv/WKwaQXCZauL0V4nKea1X1rxsU5hqlio9kfKEk/z8wYUCyDyAckPpUHSMGXiVFV+Z7o=", "algid:sign:RSA:digest-PKCS1v15:SHA224": "iIUH2m4d6RThcOVrP+CXItTL6ZZYd3L2DamMCkLDnwCRruP9c9wsidK5FTI1+fLofftuBe1OV7GjMyiSMBV/ourcF/QrzbOINLKmF1M9STnlnCAdUKZS2W6erc9xyxYillvFivy22MnjN2vWeaRndM2fcJwklaiEeZZsOWFlANs=", "algid:sign:RSA:digest-PKCS1v15:SHA256": "WhESRms3ivNwlXOzrIc2PhdyTywdbJ8QB7O75jxr3lcydi3UaYMyig5nif/InPCmyhlaU6k/BuXt6kGuqjmYMcCECIKrnlTcLE2ob/RYcOcmbNvyvT08t/8M0P/Ee//EsxehfhW9ZLzLUeuDodHUwYncXTzaxnyeoi5yMDp4404=", "algid:sign:RSA:digest-PKCS1v15:SHA384": "obD02BmCEEKFxEoxFOuUgGkNQlUEAUYNQb0/p3/yYgLJBgpCt6QRt7jTEOrifsqSj7dbxb4N1UQzGjAnfVDong9WhB6qHaiV3LLczbnTb1CLDWnSIDRTgH1OmrUqJHuTcxG6c7lCtrfIUvFoB2u584mk0l5n7Qm0wzSFjmC0fxA=", "algid:sign:RSA:digest-PKCS1v15:SHA512": "hUPfDfsRD3R0YzK+bXmvdas/iJkA2oPY7k0ohUZestI+wi76bOFpnJME/U75LyrHeU+2PXMZuzOne+HOy5xfwG1qXoCAa45uCUkO9/1hcJJ9p7iO7zPMDbcD8q8SHQnAWw9oqOWKWNppJSyZBr1ElvIy9ZZ91XEiWRwzAUPvWco=", "algid:sign:RSA:message-PKCS1v15:SHA1": "db/I881O2pZ2ZilPLrbFvBvRNVT5rMgDJ+gIkFLXJJX8o1YxKsEGcCOGMN2yOsF3cIsepJaPK8/7O+IVtsZIlkFO+7PFLU+QN8A9xQh/RAR8jVSxZEmlP/qPPJ+W+hv8HUA4WZ0Azb5VLchkO+z9UFNLxeD4qsm9a7wcLH/pzFU=", "algid:sign:RSA:message-PKCS1v15:SHA224": "IvnbMwj56jret+mw/IS/LMkw4PySyx0pcTmzxLIdob6o1tq9oi0IVWgprZ2AI3QbjPN4Q8wLuDRr/Vx1GAZ5Ut4O3UhxNQAmbgpheL/0180Otl1GE3lhru0Z2kOv9Brdf4Ro7Bxq6bPuZHnlHI21WTOlHis1dKPo7LGnBm/YW34=", "algid:sign:RSA:message-PKCS1v15:SHA256": "pw7oXUjREq688eClmI/SyiHwYpq7jwbN/3j+zVlF2xqtHkEbz+goCR0v9t5h3zjnYPPh5KtIRbNxm4a+LN/XG5i6hcGrslck1lukqolwhixt3e8spEzek2QgTqfcbdE8W22A3iv8zd6ofeTaY7BMZ0BfKlUVCYQfLFbRO+hDzkA=", "algid:sign:RSA:message-PKCS1v15:SHA384": "eOLJQCMSJbpwdRJxw3wFQdPD+Zrg/5T+PcDScLmtdOsGwXod01oEhdsADvpEotm1PiGazaTea8V6o3Fi1C9JF3roykzFp5T8oo7vBZ1RtajKc7RTUpvK2RcbhvgTz28jV6R9MJVJSaqF/XlZTrVbXgCGZ1pppArb2Gq42NhlyYA=", "algid:sign:RSA:message-PKCS1v15:SHA512": "QExyIGSV2qN4+TJikbVzOlnKbz88NQTmp4/oE+kJzS6XNhWAYwEz1I5av782lesQnnofuUixEigX7MKbtB2//Mzl4TMxojNfYheo3F1e8fm8qfpOtH2/RYyrxJx6yTkRj5/tlcSwjZHs2shgmeh4vc974kq2LkDvzDprw2f5e7o=" ] ), "CryptoSwift RSA Keys!": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "iN/hoQzpwUzgEEVTgQX9CB8pjv77pRvcHlh3GwLhTdHJZ5DNFOsigroxJxT75ms9Y+s6q/ogRdv1F/yEsetQ+51NdO+IaWs8cN4kPAOlTYZqwc6xdsqvxvKfDhu7E8tLuofkQDIIUeoXnDDOV1zBCzCs7/TdJ7aVZCh++QQoWlE=", "algid:encrypt:RSA:PKCS1": "sTfXJoFBif4MGfcg3AjzPxFfM00B+gj4un9XmNw9AeVQbsUgx9/GayhkvNa1tgKW+u47jQcY16ZhyceTxBF2Aoqh4D4gVoqPcenEIxsnAYQeek7c/cp0hDk3SPNZ/+eSxeJuAV5/DgIttT35+TKmzcwNdSndCgm6dY+A976NQ78=" ], signedMessage: [ "algid:sign:RSA:raw": "IWL54w92rMgBR8HGWEv73JYBuGUkSmnA8TCN4HKFRZUpA5U2BeDSp8Ip89C7oIYACQ60INGXaUWeUi+NSXurgKJEWfUGesfzzfhyTOoHxOopdNyNEdRLsl5HjV4HMPcfuGuwOQ2BNbMWd0owTTKiKQRBZ6ktQ2JMRSQcw0uU9G0=", "algid:sign:RSA:digest-PKCS1v15": "EBB/AcC+I4SGvkDQDPRYgRY/P8bWdcAOaoCE+0lLXDH8omLd1sQOiRbRwedWpoM2QDnqEwbNcSbHXnRgDw3UIB5P/DURizip4oRKPm//vsGZLCQAzPYTvjaM7GqJ5/mvTXOl63XRa2deYRWneA0kM76Dr9wlyvhiAfbnGmwF/pQ=", "algid:sign:RSA:digest-PKCS1v15:SHA1": "", "algid:sign:RSA:digest-PKCS1v15:SHA224": "OwaWORrWAby4M5p01gDLHCkgX+uMFbVKLaSqq7g3yc460SoNUOS12uLXLr4+c8j3H8IZAolASn/ntgDM6q9LaDEUT3QJA4ARDLNLPbCtzkM7y5ErEo5/b6Q25O+mzFIWoyh6O473s96teTaZ7FMwCOpcH1hO19BiX3Uay+JbFrw=", "algid:sign:RSA:digest-PKCS1v15:SHA256": "hgde5P3kvsn5+OcPgMf6mZEOOMAtOTxl0pDonCRXVXMrBIjZkOkSyeonO7va+cmblHA4wa7Pak4dbm28vVMH2qKuVD0OQHY/3bvxef0plSrW+U2rfH+HJLhj1u0ix/rwG0D7WiLq0tyHmNZq5fCL9V568Bff6QiZobgb2PgiQ6w=", "algid:sign:RSA:digest-PKCS1v15:SHA384": "h/BWo23Un5vGlwRHZg10E/P0hVrO25jd1tSftyaWW4j4bPafA3gnFvCRGNqN/Hs3R09uEJZrqHnnDf5/B/MHfgFx7x4gmJ+KmHmzVQt/+ZGs3Gv7y1IZXsE0PmhIcN0znjODu3LTHR3NrY8mxml/ZIbTw/rUcD2O7GjyjJsceX0=", "algid:sign:RSA:digest-PKCS1v15:SHA512": "B3CEn6LZlIqrvGTPOVEqGuB2Exn+9iGMIn+e2r2MvuhkJot9hoT6UBne3jWDhZT35TxssTelD+z5hyWemqGulaiBwccgKSfIVlqL0kGhyF45DQ/f3wRHa7gqPdGRIOHPMj1LzmqDeoCXc0Lhrn8vmQPC4IG+oYJFDUSpBs3S8T4=", "algid:sign:RSA:message-PKCS1v15:SHA1": "NaceD2P26yV5uN31I+hKl7dlIh+JmgpAL08EWxFkIfTkfZN0kr4753AOsN+fjz1SQngGy4sxXJJIEBwrpK3YMRIIVPWAlO0fX/ArZzaSLkwDqR8Rau2NTvpUDj5hzZD72EaJscMMvt4Y1LY0VubZ9jYmFjzLoOVxs5k6YgtHZII=", "algid:sign:RSA:message-PKCS1v15:SHA224": "G2O/fR7XumApE3hQcZifpeQeCs4pmAXceu9bKN2FKEGj7q7KWShSUnLyRqVO7N9ZDFn65uq6zyEwR69hpg9eKsCQlZ50tnl9eYuDgmAshQvu8HyIatD5vPSwRRN1bjKr8nSQ1UVurgkNkcLw5VljhOW33slzD/f3tfUCfbXGp5o=", "algid:sign:RSA:message-PKCS1v15:SHA256": "SESOLgXnybYNZtoQj5onqdNQbN9ZqTh/i4FrFdAkVgRK6yt6x4Lg6kSMIH5/oMBFLs7XbTmnkKMkOrmXPCGT9jJvaD7axtZCeXuBx2GFhMfaGd3IfH/4ZSo+4r65BmcmnhYnlqB6/ZFY4Zyczqh5eVDe1moPm44uN/evUWQV41A=", "algid:sign:RSA:message-PKCS1v15:SHA384": "F8y4UQPGMioJIUrxAjYIV9OYMBJlKb5e8EQXHmPT5JauX3ejkkqyjyQr7Q6H0ZkBnnG0VSrqHx2m/3MdGzXDWFcgnLRnrv+i0trppUPSMYnt1LcW5uBjsg4vm4BLW+Jdp4uzIK1JdInfeWmBOZwa7QwrhK2qWHHG7eeYgdnH8c4=", "algid:sign:RSA:message-PKCS1v15:SHA512": "Xc2GvDotWv1ld5uVNGHCL7sHxv/VTdcxOGpG7xbYNyrFm7rnZ/cC/+RngcJpXUZEVl+kuafBt3peXP8GmVT2iWyFqhCRoIaHQjordWQb+kfwCuaMoOddsizm5Pj2Krk4XLJ6vkIAYKRmLVrhRPvAObDewMLP5A5MhdpHQUGAzHU=" ] ), "CryptoSwift RSA Keys are really cool! They support encrypting / decrypting messages, signing and verifying signed messages, and importing and exporting encrypted keys for use between sessions 🔐": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "", "algid:encrypt:RSA:PKCS1": "" ], signedMessage: [ "algid:sign:RSA:raw": "", "algid:sign:RSA:digest-PKCS1v15": "", "algid:sign:RSA:digest-PKCS1v15:SHA1": "", "algid:sign:RSA:digest-PKCS1v15:SHA224": "", "algid:sign:RSA:digest-PKCS1v15:SHA256": "", "algid:sign:RSA:digest-PKCS1v15:SHA384": "", "algid:sign:RSA:digest-PKCS1v15:SHA512": "", "algid:sign:RSA:message-PKCS1v15:SHA1": "sQ0YsWQGbYJXwbx+0BlturgU8TJEyYlTbnJo0D5gcVnov8XG0ptDVM2wCXqhVM646nH0HiH1eOOjXZa25uRD8P1WwkT4AFsZxmMOm8TOn+h5H/pas7V+kG6qz5JAaQwrgaFnejCtcawDgSInN+aRdnNsHp+aK04Z112mHaNR5OM=", "algid:sign:RSA:message-PKCS1v15:SHA224": "kXESCymon7IJ3YGpBiMwVW6J+l875YMPtW7me4aGvZrrRvRHjAPQDcqMMKPM6JKOb8cBkUM2FhC4uda9J8X0QZku/PupFjBy42A171HU6W9K4e5MWDh6w5FDTg2kyO1VhcLgtqGjPxx2q57+UokggHdXNgETDboEKLhiTkLwVZI=", "algid:sign:RSA:message-PKCS1v15:SHA256": "yhxz2RERdhE/GB8hAr+Ttca6YVKBOPV7AjsQSGRaMTjDXsw4DZDYqjHAJM5xI34yPmXzfafZ+jd5vzkRBkMRHhzlqlCyZ3EbMbykIBmCGu/xJI1Ppapoh7LlCUnC5Q23hUg+WSfNcpaaIPyqmwuuM9vk0UrkH9GWLbjQFg/PalM=", "algid:sign:RSA:message-PKCS1v15:SHA384": "cShFP8ZmbN+VACN/yGRzlFPEVLcPuoGO/CIRvHBQrg1h1kEhyp4JJmFENtKpPWQEWNInrU4zeONa9TXxGnq4NcDf5bTvwcCAbxf8vRl4swlWp7HGYmkgNbEAbR4/TFUOvZ9LN/PrFP2xWr5BSCkyTw8R9jRTHeZFa97nGq72GA4=", "algid:sign:RSA:message-PKCS1v15:SHA512": "nKKmZx9ESVArtJeZXLS0bPVyLeW01hN3i9jXZkv+DLDPUkn6wKA15U9bGV0LEzRhfGQ9yYj2DnVpVBaviStx/JxYL+r2H4qKJwyzaqE0rB3pZiqkxMrzCleNNrx8mxRfdoVyXpFXQLd1jLOnDz7FDFn0m3ChCJSzEN3ujQ+ysos=" ] ) ] ) /// Non standard key length static let RSA_1056 = Fixture( keySize: 1056, publicDER: """ MIGNAoGFAKWx6RJnFWkMlZnnGQcFm3qe1pcIEdKY74OW/9K7VGF/dVw+CKfPqGHC4L60a30vTqnhpOP6TA+vW0EZ8Jfybe9ARPmbbHknW2beLGHo/vXj/+/Ln/3o35JfExEwIhtS6Go1gAnGBmjBCbIpJ/zgDcoVyFB0qUz/qSGyCLwG7vTXYSuaGQIDAQAB """, privateDER: """ MIICbgIBAAKBhQClsekSZxVpDJWZ5xkHBZt6ntaXCBHSmO+Dlv/Su1Rhf3VcPginz6hhwuC+tGt9L06p4aTj+kwPr1tBGfCX8m3vQET5m2x5J1tm3ixh6P714//vy5/96N+SXxMRMCIbUuhqNYAJxgZowQmyKSf84A3KFchQdKlM/6khsgi8Bu7012ErmhkCAwEAAQKBhCEyNanUMTvso4REAoWfn/i/HesAWOHCdin89J/5m/w0lwS2APHt7qQ3cOOELgzUj4QFiw2JtfdmgHfYhJVMoq3OSDDbVYm5ubWkCltl++DT8R5L2dxp5sWELQVAZi6Dy7137yhPKt1RU2ArnOlOGpIM76aG8ONcsc19hPW4Dr+bnLoCoQJDAM4E9j++YPEaShNFrK1mJ3VS01M4Ei0lsxfZ3NBo2PcyB+pihhSQSqOAwsXEGamohdTecZAsWS2sTM+MNQ7IV/cSdQJDAM3kj3jeZv6aMuGQMGuDJmKWlp1v5F/nAfgPvYjMnUmHkiqS5VrG3L31Y4VGEf5a5idiwZPtnGsMHtQ+bmlYxLLslQJDALojt43eZ95PX3BMOnks3Cff3rnI5ntOHaNGH4FZyfaGiKpXvEcmG5ngw5pF1N36OnkbRkX6G9TtYTUAvAuQLhI45QJCfqeaJnVRkE9U+3LShmCQLVeLYV/icahOisVMB6ovG3tdS/k/Q59PTT91sBdRnFFYgWP7xr8FWMiE8nVRQFbN8W8dAkJ52r8vpPMhq7s+DVCmpLocL/A0WXsvlsdPnrE306pqFkyIs5V9M2+IQy1SDutqIWV2POInkcrT9UM2ubydJSTo/Mk= """, messages: [ "": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "algid:encrypt:RSA:PKCS1": "" ], signedMessage: [ "algid:sign:RSA:raw": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "algid:sign:RSA:digest-PKCS1v15": "Ul+IsDd/9H1e6nB07lNFyAXz9WRm3+15s/PVwAMrWHUz/GGEu0FCfA2hXoet2nrYXMVxWCUu1jg2bijuL9KAj90A7EKzEK+dMK2GvMRWUJjvLqAPX3rxBwoYV5OV1ocwh/bVY0Qsp3+BvL+ehkTmYvLmuYoJCRrKL8y12pFbwEraIxKs", "algid:sign:RSA:digest-PKCS1v15:SHA1": "ZuSggaLg1NXJjJlEuMsyZKHSTXOQYLYRwem1g8MftBQuSDTDrSpGalAqAqtFOdhBGUew92XXAzSbrm1qUvTvDy+BjdgdAOaDFD8KIg4FofKz6gAnKNP+eX2PJgZ3mpP+3K4YyRCt7RAHVfCbFcyfh/Fazrv44jSvevOgxXA1LLAbvfvn", "algid:sign:RSA:digest-PKCS1v15:SHA224": "jQlax0NxM5VunnO5Gv+De5TrhCBHDSSrc86R2BNpCuWQRMXhxX4A/AAszsMHDNUvrImz0/aAvB/iONh8mAbc0DlZ2xRFx2biVVYt2Jk4bmaoAJUDHveLeu1rHKzSw+aClW+LcQU6eW9SQZVa6RKxVtEoag4utHGdD1gySAm7z9CLgvBN", "algid:sign:RSA:digest-PKCS1v15:SHA256": "farZtjPK/cCeKhiYbyJFQmMR0F2aVLv+hHOyoHD5yQDMDzYaVU89hNaD8kvvugLsvPgaj7AjQ94cvrFGe8WdIgZniKSzMlY9kBzDIkKYLD4rGZ5AH25/YcsIma/qGW205EGb0BmCSBA3C+DiBn6O1EgXbrYG+FbIFsCEriHQniu8+ayp", "algid:sign:RSA:digest-PKCS1v15:SHA384": "BzXjYK7NwQEp0EJaq6keOLBRQjTG5R0JW+2zDhzj8aDhlXDNwhrjLLm/52RiSzTx5SLRG6IXC/KEUPNeG1DcXFIX4hszXdYdZ7gMQJ6TRmefkQDln9qeP9o76BGT6ZQVEoaRqPcLJe8ndRRVFIeKtr8Ebx9FrmWdS21vd7pU1j8bxLM+", "algid:sign:RSA:digest-PKCS1v15:SHA512": "fLQXVzoJp2kPk7i7kXVw1FUGgM2qoCR0aPoQq6J54zUmS2ebpDkVveQNWUG+YDJfRlle/EwOZvx1JUeoijgtKzKonJE8fmKuvc0Mb/tTzr+qlX722GyPQZrop5XeKY2LjtOm9i/2EaL777FsSdeGuYLi9cRZ6I1a5vev2d9mOPT1KPFZ", "algid:sign:RSA:message-PKCS1v15:SHA1": "QLHLGgW2uvKyW5EwfLErD3rnSLRusZzCnE6Zz+m9b6q029FzY/9kpHnhbWNE9NSOqSV74KUXJL26lS718dnCPl6QaNbiLSoYPNzDpf+u35xtMmO0mUXvQXyL/I1eBiuXy5V4RnrVJKsGZ1PxnjHwaLf0JYxZ15FmCJDLGVeFcqZeRPct", "algid:sign:RSA:message-PKCS1v15:SHA224": "FQWd4tPg3zTk8dsq83UFgNcBQuWEjSALDp7v/kWPZBhCCs+pRpxhFwc52V4MfrfZfAAf8biPCY7yRA4EeBhaTogoUobBGJkK1NNxSDmv0Oosf3quqNVPxDBA4uIYXY8G4+MIT/9Pyd4Ii648abZoMW6mH6QL1wHY+x3lb0f3+k3GcHjj", "algid:sign:RSA:message-PKCS1v15:SHA256": "Prc9aRCeqTNWSu3KAP92yTlTf7TjbAc3ZBCJxvlLmmcELxl6OHdEBHK2NsFvOybW3QlONdoZOcwnMugFppIyFHr6fKQ1afUpJ+GfxC33LWtgohx2W/gp0LDUxoDNSkJOboMk334RyqDsJMMgq3cUf2vVCMgyzTCEIRSkIk1ImaxPDwYy", "algid:sign:RSA:message-PKCS1v15:SHA384": "T3qAgzZwHv2ks37o/RYxEhEREjga4UI81j8uqGJrrwhs9xlO+ZTAfhojMLtYDt55nt3FcUNW50z5ZwGlkLoUFY36WG9bvQobFAKccpzIwrWpJZcC64/XejAdn4kyHXPJ0WcXXE4Pw2MyIW2BXOi2rPQmYaxWtz89PhsBt72a0VmmFEFn", "algid:sign:RSA:message-PKCS1v15:SHA512": "B+koY5fGvU1OdFkzqygjBJizY1j6sP40BZ8A+N+rsx/T5EK9yluQCrmdo288E8bhqlkSe27ptPqYEThB0+fhuRhmAhbKSZZtZ4jedgG4ZWNP3r94/pJ9M9Vg3y5N26karpV0FYaaIurCWCUP4D0RULMsOXimOwVIruLPyV8WJs1wZUHV" ] ), "👋": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "I/Bj1wmy3I4KJfYpmArvWFf6pFJUsWXqkWKnx5GDGuLByG+raNmP/GP/YCAvYLqxyeZtRVg8uDe4+VR0taIGV/KVb2G8HbOFMBGS4888IAxWY8ovRFFpRTropAxS+ed+0K5+RG1h40cHVw7E31lfsiKIA/hExpTTnIsjMNnN3oa+u/YR", "algid:encrypt:RSA:PKCS1": "OgMMS3psCcBCvaitf6dnrglx7w2rQSWAlgRJhzGNWXMdAt/YqVQ6x7RuI8d6y/pumsrLCkhVL28s1hp8lbZfkIp6c8bbMjpy7gMM3d72b8GOTiJU+OJxerMa1jGmO9tOX726V4vsjEu/Cq0ydqbzGMKde5QNoBCQLQrRkluPjRNvdcyy" ], signedMessage: [ "algid:sign:RSA:raw": "Ba1OBm4L+q1rTme3HQzWP80FxiKhZ9GKC73hfNhZ37vm1MZ40yULXI4jV1iRX4Oheh/tXvyFg0NJT6OXsSDQeV5vvbu52QCvEu1O6AxGx2THXkNRCzd9enOIsmqZrpI93+iXteyG0oUDdlO6zMG4lAYOE0YfGJheXFqy36+CSmPNFscj", "algid:sign:RSA:digest-PKCS1v15": "ZxzNTDc/mUPChfyT5/ZQDmwTMj7MAvAexQiWUhxwJFJ892EOCWQTdDsi7zIYCSvRaZUlrLEHsjPWUr+zJd4fsCFWwLKTDBJjL6b4AAeCsgf+pwgAinTpwUTwlo68XYON6WGlx0QrPUiK2USpvenIkK3m1khNwNoFAJOn/YVlsIXvdwgL", "algid:sign:RSA:digest-PKCS1v15:SHA1": "TtD+8Izo4ezCAvEh/yddOMD9mvUSWgSmHiCCdtu+tMAVeofrADVcQqNjDjGPJw/dED9qVDTZGBTyJ9K+IuDmG8JPDBzjWVBi+s6Z4d/7gfqQFw2Iuvsx4CVzFK4IropGWo+6WnWZaTeLSKmGxAt6tV4vQ2C+DnoqYt3W4PW1F+mE883m", "algid:sign:RSA:digest-PKCS1v15:SHA224": "T39ye0Qjf5vTraEoVXJn04lR2M3e2TfDBMiXSfXAaiYwKfWr1wShVwDGnqYTDgWQujagSlAnKJhb/GsPDUl/IZpSCG971yeh5qIDnsqSbQrSm+DaXimKQKKPBgbCgC7kxKUsR5zmabzu1c4pOkKT2OQvHjokz5Sxox6CXak5Z19Ih8Qx", "algid:sign:RSA:digest-PKCS1v15:SHA256": "BljerZ9FCn+0Bo57yvKsDHuVPd8sLGOdRN4R85l69FJ6if+V+uGQI6rWHpURs3wRRNY0hGkcU2snfog7obIcrh6SsGeT0JQNEjDZINDJ6/5rjFrIJGxMhsFYpqQdAF3GHx7RJFdrf9O8j5cJ6umVpFJ3AwQxEbWTGWTtfAgyHZpv5CH7", "algid:sign:RSA:digest-PKCS1v15:SHA384": "OQoLeMUtktY+LjVxgSGSoU70uM2kJCz4PaMRIdNquNk6KvuCz6x7tikuOzno3WF4UAz0mOnl4b/exdI3X2j1oZCwwfCcaHq/5tL6mCxaLXZ6zlyvdkADt+lHp8MF3xz/lp7ahbn5g3gkAD+Y7dLqZSRgvRaaN4lXMQR176BAXs/wp1JR", "algid:sign:RSA:digest-PKCS1v15:SHA512": "LnocrE7uaCx7n+zRivY2y4vzWnzUHlr01krZXM8ONfbJ5+ZJx3m+uCD8GmUzIRabKz+E+c28wurEicXKhKE8qETGRIpqIa9sTbtO+76QA4Nb3W4STJclNt4RKK7BvuNxtoQsrdCqCuZYLx6OYyuAB3orjw5vXHOyfCMui/UGiyehmfj1", "algid:sign:RSA:message-PKCS1v15:SHA1": "LxqCh4V7k8iBBpluqHtBx5MqQhNYK4wsOpiMiaqLFASfK7US/oH7yEoJvTmLw+d25++4DQIYm2VP9DWsg2nOPl38TwNPXvCrK4eIw5wh+bqFgKastgLcwyETOWYD3p+dOe9XkFGQjONsVazm4FEhE3N0mvm8Ypfn8uZ7ZQm9tA6uH9++", "algid:sign:RSA:message-PKCS1v15:SHA224": "d4LnV/nlcvnbjCkhxQCWksR+moMP1knLdurLTICDsUK8HamiYUcs35H/ygVBKZXQWcaHjb3q9suJ2xCPYH2++Z0uzvvH/YOnl5JW4v85cGopK5IfiLPo3jfYIUnMqJl14JCOhZz+LFptVFKJcsj+Q3mr/fV2h1L2SVCl0E01C4kh0Rsk", "algid:sign:RSA:message-PKCS1v15:SHA256": "QTeXkVdRLYZxW1V0fQ3UW9iJdtjXEMkUPVhG3UH1+CPeOixnjDgVEZS4+kqoNkywlZqOgFS4QO4MsHwT8FsyCkG5tcUj3VTd4yOptJ59ti+Gy+G5s85kwmB8vgCOFABihe1pNswgIlYK0Sk6jVqeKzARWyid5btr50T4XWeKk8OF1rQy", "algid:sign:RSA:message-PKCS1v15:SHA384": "D2flaFYfEgCkkue4uFe5E1LtS7OMdrfaA6C9rnVXjB1gp25GzP7PAEanN7wCmePlmcVA3bAW/+EjT2KRuxJVsRkHl3jiKX0Y4icJnwvbnDEVxcVbuLF17WI0mmP40+/hwOZDD1wqpNjHdBbO2Jb4QloEf3BknE3ICz9HG+ZqG2qNLLXc", "algid:sign:RSA:message-PKCS1v15:SHA512": "Eku3C+NT3K/6ED/uhHyux2fc0CaYkY2mKZj2g1tBpRZ9WT3IW6CW2g6/LLtlklKj7bXmZCrwL1JZWJxXWu9SZO60WBM8Ppr6SoXKOcBu8hYqLnxdHPvfaix+ivoj/NK2BjbARkihEBwFwXZCjGNiskeKLg8h5yj/aY5qTNKyUJ7LyIJM" ] ), "RSA Keys": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "DG4EcbiXQclDJ0FCX/nbFIDPV+QXO7HD/ESi0G467On/xqWDBbrz22S5YTvukygeA3j79x4Aj5x5r6PhF216wAW2S3MIA+kAFbzFX9ywSKko7EWmX9oSjhLx6lgTWqjqGK2/zKANsbFNEtc2iMe4Ma5v1f+6CHUfO+zSoWWusIAoEiRL", "algid:encrypt:RSA:PKCS1": "dE3WKAme2QuETyEgwK1R1aK5we5ztjMuYjaNY03Zj9I7FmUtVaaMuhIkkmHg1bQm87xWYuc2ovcmfYUWBj3ox2gIy8p/jOHu54TdGEMjQoqi9OCR/ORkKIjJRhu9fploB8/U+8Oslb6p3tukLviT7XQsn3+wy9nj1iTVoRBISxBAa4AC" ], signedMessage: [ "algid:sign:RSA:raw": "E5bpDIZqS92FTfuX6f/EpFBg2n24nOH1MLAHhyXtlJokjIDRhZWMtsyQg6zwXaoJ/fwzWlhjrpCWRtd1ewjIvzujfHrt6IZxvu6wMWl9c705YKBoOGyOW5xfVDc0gFyhmwtFPZ57tGSEYFTQxMS3mhTSmkPC02IHHKUMaxmKsKQBk0va", "algid:sign:RSA:digest-PKCS1v15": "ot1lTy8Vnuy2WERztw0fjtq9VD5JS7lYKHi+MZ6155KWThsxuZIIUDgQL3bTQ8I5xxhGOHHDJ0qLOYuSEQxlsaiZBGmelCKG4HDH8qFvvedTbf28fHl7In4GIVEhRv+YhSysHrIfdtZEPnxxOIFNuTK0QxcT4TKd24ZMaoUK0UOqJxym", "algid:sign:RSA:digest-PKCS1v15:SHA1": "YayK3BLOkcjWyXufRj0m2Bzi1FXRATdqhcNF1gna5jwRbbSE1QY4MWq4MLeLin5aRtCZohfk7MzZt8T/sIxUTwGKJoe2yb87CTIZEM0DSG7qtPS7qe1DFucVEMPwIUhKgLoI14RfpPkgNTow2CjcW/dl/0/gQmeAadF6px1vwd/1w3J8", "algid:sign:RSA:digest-PKCS1v15:SHA224": "YkV14UcPKH540y+Mj7Vkp6MJnBzK1sCnTyA99vKH0RqaYgqpFXKisZmojoeXPOzfXkd89z4N7bW4JdwUk+rQdYm2RTpvnXoi7QR0JqqkN+vQ3TP9QlQLMCa2MwsuclcFie+zOVhDc2DX+TX80YdClwarwOdmMAF2e0QnMf3A5yQEcACt", "algid:sign:RSA:digest-PKCS1v15:SHA256": "CaSMBIMr3GcrGTmlcag3nP3aSUnW2qoNIJC8L4DQXdBZvAwKKflNnsqnoRjFDFMCV7G83bOG77MuZTLLVelsbqjweEi0VNJ0IBvleeohFxTU9NVHoKIwjPZks78mY3CWlYtrtBpEqN1UHPirkCciAdFlZvIPWvxwxGz0yD/IbLoANknd", "algid:sign:RSA:digest-PKCS1v15:SHA384": "Hp9/oI/m2ONhl68WYKNVCBJbfgzr3TFdZpjYOBMfWmHY0+qluQRdtxM+QVMFH+ujEp98yvgGC4/V12wfyGJZCLLymMKxhsbUF1cbFHjkEOzUSAey3rZeK85znQuUKOgpvCcnZ52MdynLX2OW9lffYHCO/Q9J1ob7U8KM8Ly8Tv4gJcZB", "algid:sign:RSA:digest-PKCS1v15:SHA512": "QEEGtSus2wpRBtY/A4Z8TtPcxchcAHlI7ekPV7y0t+JICBvFXEsbKD3C8sE0n5p8bVqcCiPmPmUB4J5m6Hw4fAtt4GPngU6YnRCiF4nehYIN2V+vAEDY8kp8SVIlkF0TbFmZNC5mTL1T6pmaWKoAmiuCJQCyGfitiNrYkHqcLOky4Rx1", "algid:sign:RSA:message-PKCS1v15:SHA1": "gn53c4z/u6DWdMpT2ieR9Osk6NSfVkizCq5FvEUexH3CDol6mjAMotaU8im07PoLqU+CeI8Cd4PrD0JU5N2jTV8mBAIy/mpR+eE/vbsB56EGS6hBepMdUMgG3Xd/Zjd54rzw4+tEYKqT2YOxWHI5FLeTh4vXOMnBAs5YSKtv9mepZEV6", "algid:sign:RSA:message-PKCS1v15:SHA224": "n7m4+xtV/i7+2Xy/s+Lrn+FaVM8b2kEYlrMQ0aOOYCMncBuE3LAF03+xygE+3FsvanLbUOSHgfDx2drRHPJUbJ9DXyi16QN5E7whcoq7gpkzYDn8MuwID3pTtpoNX+4DAAyWY+5RAay+Lyn7OZ2zO7xul/uKC/x1o9mRb2J4VkeBz616", "algid:sign:RSA:message-PKCS1v15:SHA256": "WM0nFMDu5HsCuRwNu90O6Y8AAr+6DzE5sHfEimgoRuncnJudG2Up7XO2PF6KqU+x2ieKWSJFdX0zlDKSqloADHuqwrOfY6gb0JycGwJQygwDFher5P2vIU1vXZLLkLLtqStN0iQO/GuFFx21J6U2g63G82TU+JUozs9dHIxBs7clQwmp", "algid:sign:RSA:message-PKCS1v15:SHA384": "AkBqQ4+6ljxcuYbeEcTI3PbpeghLHZYFxr/OGoiQJq74xyaDfsUsVQ0dQ24774zzI2VlHcIEBvx9qiFNknthArq31UblCevEZTqFzIAHBzLbwQQwvw6LdWOyCqHBDP5Ltua/H7q4A8BqKdF0bW6hN4DXrQdGPQDkwIaj1IpmaQJT0yju", "algid:sign:RSA:message-PKCS1v15:SHA512": "Gx+M8TOc6smAFLDpm3CjZ57hiH3eiEWlqyhIaYFSRWtsjvO0l5J+sa0Oy1A7zQM7yQsfoFZ25oGUJs/cx8oXUI54KiepX65Z6iQCy7pBZXgy8TWCrRZO/xY5l5Pj8ipRHyMkgTup5wWXpfxmwuQNMW9RUNVeyx1NIl/JgJdEpaE8KAaV" ] ), "CryptoSwift RSA Keys!": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "f7+Czhp0Y3kg6XPfjFjGoueJ2xorPtO7OPspMPTBmg2AsVriozvz14FHXkjxo+kRnM6ZKz+iN/d/JoSHERY3AWQ9Z3uVTSVx535PxZYOmKgCvzmXylEhpl4NK5fQKV+jaGNCI6Cl4T4W41HRZUETBAiTSWhwpTU/MOr5Xe1XSl0Mp0rE", "algid:encrypt:RSA:PKCS1": "Fl/Ex3uU/lr3v6iD345HW7wodz7v4msF1nu/LLDH0vNADhHfc+vd4dxT3s7U/qSNQEIuwBeFG12KEpKWhJWfEzXYPK5zRvSIhIbeaAlIpsJb8O9Qa/kEs2Rc5LO9MVMETCnj5yDDlmeGqinV0lVC7E/mycVTug1Jr0ELfb0Df6lhMfql" ], signedMessage: [ "algid:sign:RSA:raw": "m3psMTDc6xYFEbBuE6J7AWqEYGQIy3FwDvb/JNcSSuUiPR9w39nJRdlWeAUrS1qvxnb/ilMY5zoHNdK2j4DPt54KCthByJkZ7Xy9QsQvSgoVXJL9JusH6UAYJRIVQIpaPwrJnWwCpR6ttzGaPW2hBIO/6Df70xDCPSRJB9I1XbWF1VbL", "algid:sign:RSA:digest-PKCS1v15": "VyWICNXgSpWspn3GoClUw7lKyuS41t42R3msGUHsguneCsy8BHqX8ELgyGee/C1LQvNEGPn4NhvDRbopX712NzdAww8Xo/6vm7uNo8NIcKBZbP7gMrxU5S3gF04c7AT5vtmVCPfjOzw7f+WUjTcInYVDWk3tHbA17gMlSyDNXx0U6Xdx", "algid:sign:RSA:digest-PKCS1v15:SHA1": "", "algid:sign:RSA:digest-PKCS1v15:SHA224": "eUEnBMwJeSLWdoJwTfvDwmpJTtnAZ7w248cndGIrFyF8950ZF0JUZz6scm4qCqsF78DEiOFveGQTNKqiuPIXw4FOWI/LqZq2vPRLp8uG5dVeeaUI91+cYzGRBIdcTdDebSMOPbMoNguC65y9bkow0broG2B64S0kkrNp4XB42rOx1NFt", "algid:sign:RSA:digest-PKCS1v15:SHA256": "gmKXCAqltCqh4N1BXOLsGPTgZRc3oCdPOFnExGdaUcBwA2fIWtT2pNEIYswQyWwUgBjOz09PU9hSGkHaWHzDq3gdSUfA/99rxlfDnIEA5JUHQ4FwCXEXVNXVFdPIUtJ5ODmz4uaIM9IK4WCACXTp3nNB0B5u1Vk+b6uJnvCUy0XSAktG", "algid:sign:RSA:digest-PKCS1v15:SHA384": "CkQP2tyiSj2reiwv9dDFoBEgTnXrEcUDpgstbKz8y07WWc0jnnAtbA561vmCTcnN+loKisDuBzB8sj2sH8bQrUAr/Z4SGopEtxzilDKWqcg7wRT8O32tNkzctWvSZHcRTY4orkjpTNRG1We63fVWzGtQskbQFgqYjRc9pAWVhBfuUTrX", "algid:sign:RSA:digest-PKCS1v15:SHA512": "b2I38N81BQ84NCpus6qGgY6lF5WI6Z6nX92hKl1nA6Vx1zceivvOYLhT6WV9aAO0uXwRMqxXbheHBQhSgQemo9cWLtqQ4YhZwDK8Iz3tMhtWkyJPqQlci9HLQkOcQ7DlAVm7xe6+a8Eo3Ny9TDRMFk2/KPCrVpdT6Ca7LXc0tl5v3RI4", "algid:sign:RSA:message-PKCS1v15:SHA1": "jwXobxBq6bzyzALQLkR8CZ2zZv47CD0MnbuBqji+JBh3w/B0GjovRhFA5O8L+yQxqO9GmeGSZMvetjsqmkrN4TJyj4+bLw3OmhCu9zf/A3Bayk3kr0GizhTiUxm0pMVuILpOCa8SKh0urbnR93F9F1wSQmDEMmdLEFTjje9GduBkAvgD", "algid:sign:RSA:message-PKCS1v15:SHA224": "k3Nuv0ggnUtLf3dLY8lNkig6JI28g5Ya/t6pJDmCJHfdAcdkITfX6pQjJ0/nbTucWH5v8uAjpBSxdCx0tJYv/UPqfAhCbmImstOegPIsfZQGaeB/JAHRDQ0dxsoyF6oEvpYClvQJfGzhulRfrMz3xYmajzoP/ZLB+9M6tmM5I502btya", "algid:sign:RSA:message-PKCS1v15:SHA256": "TyskblKb4z9x81suow250RIoPvX5ZMsDGo0T9mzsaBmUTMnCFfx0GkOiuMEsgkv2pDdWgWknJGAyefdF0ctIF4+WTHnQy9kd4T53sO9lXUFJprvMvvjPJid29xDb1a2U3RtmQawcF8pzCtOUm2FxaEcj/koDsV0qscgW35JdFvkzkTDm", "algid:sign:RSA:message-PKCS1v15:SHA384": "MR2T4A/3GgWLJYHDh9wEPbu//ZqDhqNQVxTu3EzbxF+HO2wYctTLb19AZehe7KT/NCNH5lcM7jeCY1MCxyl2Cy77OJh9J7voayw5qh+ugBBJt2CCcqomfUHEqEosR6vdywqdRkn00Y24krCsUUQaQoc7VqGYSElJqwUOgTPXsDRHe0Pu", "algid:sign:RSA:message-PKCS1v15:SHA512": "f+EkoL3OoZHjoVh3gMx2y3x5LH8D5dwD9YoYWXwUiOjDjGWM4LFYI+ZKOy+omQtEcngWQEWKv19XROQMu3S3/T0JBfM9jPvM2HsXIA5EGSa9aR1sn/E8I1s8ItKuPPNA0MxG0NtfCYTWxUM/jgy2fuwaA0lhE2IW0WpbLnanW0MQFL1l" ] ), "CryptoSwift RSA Keys are really cool! They support encrypting / decrypting messages, signing and verifying signed messages, and importing and exporting encrypted keys for use between sessions 🔐": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "", "algid:encrypt:RSA:PKCS1": "" ], signedMessage: [ "algid:sign:RSA:raw": "", "algid:sign:RSA:digest-PKCS1v15": "", "algid:sign:RSA:digest-PKCS1v15:SHA1": "", "algid:sign:RSA:digest-PKCS1v15:SHA224": "", "algid:sign:RSA:digest-PKCS1v15:SHA256": "", "algid:sign:RSA:digest-PKCS1v15:SHA384": "", "algid:sign:RSA:digest-PKCS1v15:SHA512": "", "algid:sign:RSA:message-PKCS1v15:SHA1": "ZU2t9DVxdH3xyeayRkYOvij+PaAn+xZMoL1PTM/yf0pBdJqkEvPzg1JaSwMQP0sgCS4zfGtOQg2vRdDsl48uYASUUn5e0k1mqfNi8OFEFCIAGBreInHwNS8GwX7WjdRvhBgdkf8/SQUoo3RitIlRUSi1tuX2dxSeV27e2dfy/UDqt3yZ", "algid:sign:RSA:message-PKCS1v15:SHA224": "TdOQeZdywNUJSlQUyO3gt2CZhk7exdYxW8ibHKTxAckSYrYpGSDLnzsgmLpqmu1KQgz8bbtWjv0aPEmf7s1HkHnBcwmG9yIMZ/0JlKDVNj4L/T7fvflMHjjjmSx9hwibVME7+2pEpH2M5T6CTZHHAHviyGWjnnv9AuP7/yxpG+NjY1YK", "algid:sign:RSA:message-PKCS1v15:SHA256": "hc9zFYIijd4MdYEEULX+6aZ58VxrVcCCFLK5IKoDQp6doD7kS8Bp2VwqTdG4hdFrRP+TgS2882RGMc3loZfy/LAsG6cpY3JgtzPF/aHqO9EKxPjSAwLyWhqD+0ZsZIpwYf/tIuNIEJHO5zVr3C/NSIPLcrMXYjtmBsYJWb+3MdthLP2u", "algid:sign:RSA:message-PKCS1v15:SHA384": "nZcy0p9J5Vo58lRfvXMg/7lLRCyQZlyStkPehWqdX+rJMOY5OyLw/IPpmZ/KAiHFvKgqIZpQt7KVHeNxDmyB5yquPshyyvrwP9ter3HdFVXgK52rZqmQMpIPM1tWhnmX/EUt/6yXQYVGerGXF1txHrZUS29VPsv7G1S7TaP/7KDmTC9V", "algid:sign:RSA:message-PKCS1v15:SHA512": "JhFgheCKfpA1xcubGHRqUtC6Mjc7PyzWtmfrcc8ud1AHPYiCpMnlrGvpY5p7pDKaWmlK8S7Rznl2r4QFtmEWt1de0vN62VH5Nwi3kSi6q3ufvjpGqKcH1p12o3dMM4qbS8bbnm2bIP5DmSOKAIP9Acd1ixlgomioCBsS0mm6U6sbZlCf" ] ) ] ) static let RSA_2048 = Fixture( keySize: 2048, publicDER: """ MIIBCgKCAQEA3HI7SZJ1iiQ0b/6ow546Se0IuxJOyAqK854X/uspeiIVUzhDlC0cvUEQJjmo+ZfitKoH94eV0RulbbCjNUV0x/1OKonKJ8anHQ5tgwfXu89EO/zAry7odLHYTvgBoJXcM7sofzPdFuwUYXj/G1CKO3EVvF4sTvjFvfq3huDdrlrRGuGip9mWTvcH7VMFOPbIhLWWgwMyBp9AHTisQCA0YtRdnSRv70dAcy97ys/vy4Hcf2yV5HlryFt4ewR7YD57CSUofxsH2lZt+1uvQ4OfyjKvwN7HgrGUGL7xIVxddeAK8BeZzVAyp0sroRwNYlvGGRijYyJUut+xnB16lnSafwIDAQAB """, privateDER: """ MIIEpAIBAAKCAQEA3HI7SZJ1iiQ0b/6ow546Se0IuxJOyAqK854X/uspeiIVUzhDlC0cvUEQJjmo+ZfitKoH94eV0RulbbCjNUV0x/1OKonKJ8anHQ5tgwfXu89EO/zAry7odLHYTvgBoJXcM7sofzPdFuwUYXj/G1CKO3EVvF4sTvjFvfq3huDdrlrRGuGip9mWTvcH7VMFOPbIhLWWgwMyBp9AHTisQCA0YtRdnSRv70dAcy97ys/vy4Hcf2yV5HlryFt4ewR7YD57CSUofxsH2lZt+1uvQ4OfyjKvwN7HgrGUGL7xIVxddeAK8BeZzVAyp0sroRwNYlvGGRijYyJUut+xnB16lnSafwIDAQABAoIBAQC2Jo1mlWYZ5yCNCddZC/0N6JY2PUJreIqoEhGxyY5UJKWKRgtQ/JWqq4A0laBR3Hau4XAD0DyytC1VHYc+FU4RkfRsob4wb6zWDX3frzNLNFAlYQu1tQTOp8UcO0Dc9/cjp5omwSwGLLwKbngckcgmpaJYK1hhSJ3cBLZw9I036rm+EvVvkwOh6eSZYgs/5H+sANNOw4YvnSGYBIvrvzcu1XmBkJW1kcSg9OYnih4G5Ac6/etDCg7w5umE9IYq9b0GU8Zhlip22tsCi18ACCC3Fb5Ki6gokyyjLzxSes28QwAVUWC6WurbsFTRF0Lw8HC0MH6r2XOwWXX/7iliCCNBAoGBAPfHlR36CqIsXHmp1FX1tMYLt0OprKN7pKmY+QfZoGK6dxv2sbZxcAuNg6Se4J+r+QThay1Q2BjsoxcFHj6UQNoC8ZuesMB+WM+1o4s/UUKUKclj736qjgTbr2La5lJWn+BXohhICDDN9DdV1JJFHWniga2HgZcBWr908uD4BB7jAoGBAOPCgPURAbrkGY9/B3Sr1HLeplvaGZsylD4lXkuPoc4JRgifer7okdXYDIySFXv9L0ts0NtHUrm2l3dgp3FBQB2ewubS5GDwe4xbszeD4R/Vc3zOuWq15YLNvWBastsr4P33kW0K6wW2kYjEPpMD43jldhTszB9KV/LTwTqT4Wy1AoGAYtsC2FHhGjC+uF+UcrMz62vTMzCnyxXSbUO133bpMVqZmNOEtXhurn1IT05/6dRv5o2U+CBwBwmqS83j8i2t7g0MnfzjIfmGr2AVnsGlRv3b6hhv/cZIIRIQ2EzjZWhgIt5zsmJSuj4BOG6K/8yJXqxa9oPApSGKNiaPnEf3ROcCgYAFdpDpT/MerIIAcyeWoNiDuNt8sIqUsm3j37mXTmavLoHDiy/CjImS+4+xf3+MbdJImN+ZouhVFBAmCOd7S/lhvIEoUD6yJJKSF1EBL+Sigtg2Ui8YZCyRKqY0PXi00SSgcuPGHdDtXie3hB2MITe/mqFudw+eYIYjiPjFku6BUQKBgQCnj/UumWRvGq23MKiGMun+xFhf0t/EA20CODgEGhYvRHESGNUAq1+hFaP9GTOCI1XwlVD4oWnXfhPxsiSujycTuY6K99xph+vq0JHwkoebdrZy/usqt3kxAX7EjhjCWP1Cj57t+HgDJH0PtwQ+SjYNW2l/1sMekTENZwon1PAgQQ== """, messages: [ "": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", "algid:encrypt:RSA:PKCS1": "" ], signedMessage: [ "algid:sign:RSA:raw": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", "algid:sign:RSA:digest-PKCS1v15": "t0M+coAeAwM1hzg98tozm3v4+EAXx0n8urSdltNcuD/T5+oO1g9MULmoGAajRcmHxtUBLtcfmzt7UcKlyPp0Tnd6lqaNT3CllbWAROXc9pD/AQgICxHEZJmQdD6rHsEWCsmveWnmX5Ztj8w7XB93eEfFqfkDSTv9cMvSdS9f4tHnqBsupv47YQe0rQkd46NJUKaJ4wWWW5ug+Hbp7u5bPrQp707SIBejOYYxMIynbEMGWDn/UdEqcLPgGeozWm2KJ+77KLljvfwEHZvopuyx6kHHxa+kZHzrUOxjdKRr+Y1YGyyZrzT/G2z/CgYva/qeQkLdwprZcsNC7jCKndDVVA==", "algid:sign:RSA:digest-PKCS1v15:SHA1": "YS5QXgKmNGmOlzeDI2C4TO/Tu5uPnE/5m5EidIUS/IRcwmwQ03rFHle61SFSGJC9unwwGpMGEl9lNpVyBZm+4HzIyJM3GtyY7D2GNlcXFCKRlU8VDxjf0+LaDkv7unTRHNVtiozSs7lZuLYYq18cpvI8lgqvKqmLVSpujSwIkRm9kxDrJoGCR536/uxlA0+rOvVwgvcFEPCxekuR/Jqtqg9fZsH/l3BHkzzOOrtG8mjpupUpg0X4Q0lHJD7+oKvO+ApoKD8oiOufkXhyQZrYvqXB18QBN0DesPHgGQoH3vmMtjSZTWOsBkjafNC/Zfei8XEvhvr+7lY2iWlO/fMC4w==", "algid:sign:RSA:digest-PKCS1v15:SHA224": "hzmuMNK65BJaApJIE3NepVyXOzK0U2kfjtytpzQiPnCKeXY0XM6MXb84qsfphRedNVLzvspDCN1nwkgiOJKHYtwshCA195c25XRgeNcg9WI1NS3i9ej/r4XviRa9d059XKAneZigzQp/Pb+Q29bM7zTeYh9dG367XeFlYvxh0Bf00xXnY5vuSolTLI1yQMqYvVhnnn1nUPzeGIHlzaZ8xYSGaF4OPxx3IN4oKmxqYrvFQbh9FNf43Y6CnnyK+WkflaVdbhX+Ge+JxaQbrZKu/DisqzSSRpZisPk+9FEbqzOoW1wjZw6IrIp9OquFlIK36oVKp4+bL1h6SCIuurqqGg==", "algid:sign:RSA:digest-PKCS1v15:SHA256": "x2/m9kmMiHIa47adCIchcXRVQEYiXlT8AZr0yZkadhKm1A8SWWya28MkfR1qSNFvPtTqJYzhKOjrEXX5aWLdjTN7KSra8IyMeF8CNihjVXpvHChan8U5PCouuv3bL3Ss0xe9f6mkeDlgZrCztNoK3OliQZslKcz5wkUxZU/h/PuETnW+8VFxPWv7zCudYnn3X5t+V357XmZXFjLqnFvnh284KC0uBVOFeEhOh7YkLdDAQcn0LIse30B6FLdBBPldhqbIYjCIucIzT7Mb6a2+x6EQPXxNOc96x2eqFXHXXtNCcNwknNd6gKgZ0gV9NoeEDoWZqUqwy0RpbNBxqKHn3g==", "algid:sign:RSA:digest-PKCS1v15:SHA384": "rj41lPJ95R0pdTRr+e9m9/lFdktP1QZJ6taUY44ridX7YcgEPZn6ftnJIHgl66XSjImwZGzgFVB/y8Ekt1A+fFbImQzkn1zLUl29J0cg1qM2STqxutCV3JMDxjWgXes/yGKg8o1ZpSMjEeQ/4J0VMpbGPKeFVQL1N+MFGKqDk/odhV6rCi295zThTxWRc70mF6jcGEf/m/y9yWcDFTA5TVqR5n/W3xJaZCTnken2M69wuY7LdjI9Y9TZRa0PrVpMgq2ppH89pwFg80CVqNQwBLW15Lo9b0MMlZrwJY1d6pfhSFlZALRwRCMRLL/vROZ5qNf1lxCuomK8uqbnGdyOJA==", "algid:sign:RSA:digest-PKCS1v15:SHA512": "Df98neyN24goN+prLICyWpfMAh6uIxDLmw84u3E/SE3zJAlg0WIK12ZdeLVJ7ca5mcQEINUKD+vgSRNyW+wf2hgONCOghshCv1LfSaUxmcHBWCca8HAK9isC7i7pJoe6yn/BzN1vJNXDpkCjgyeVck7fVK1uqxqxVl6wbp6UxUmcYnLFC9VgsmMVw66F4d3L3IS+rLW1iJEuVg+TPBaABdtGkAhWbVdoU+7q8uZK5E4W7HOC9Cg7y/0SBEA83jEnGsMctGd3X9XwfXSQzpkcm3x7hQErZ0gAGORYok/3JDDVzbmsOpDTlaRpanJl6j3YGTF9pnyNiee3vJp3A4L92g==", "algid:sign:RSA:message-PKCS1v15:SHA1": "WOYji4b2Qk/TaBodcBNUfAC2ZHuB9ziP8cjsSHT0QlOVEIyQ/EHvzVEEViTcdoliVrgQE95nAdfN9e/9YFPBnVHN/UO/yD54IFSqc1rr/0xABjdATAng3sMLh3oiNQ4tfxVNOLHlXzVD3DlROZIru+V5D6eRlFFMrye+PYXMbYZNnaZ4mktcEJvpJgTI/mZl09FBLSP+yz3sZqxvVDEMZ8CAvIztzbc6pWozDNRtDfi0yWnuSPcnCF1eJHCr6DTDmsOXV+i9EUrsXABX8zs2qcCfBp/+3Q7WwLRWr5Ql90q6qp6h5dtUGJlFe8kPt/rxP7AUnI7vSRIDcqDnFNtm3w==", "algid:sign:RSA:message-PKCS1v15:SHA224": "of41mKNY5Elnz/Vmhx0t8vPi64slKBYQAOMTVOXEDa315i3pTAcqj2EomfjQKA/xET3kUqHrXRSdpn5/8k+w5l3sLetNHHkw7E6DjYALCmrJS9RiFZjlMlYtIleeRZ9bevs5OAZikzn/VIr0wj94nPwbZB46nfLJIHgH71lR+SuzgM11HNLq2XqP3PkUZ+leWxpAxZBAD+UVEiMH07AxbzGEAiLdYvqScukU9FPELGfnaLEytoLS6ANsVPOdBZ8uLcH8z+eO92cFIJhm1Tw4ap0a14TReI2EKVPnQmAj3eKhWD6zMDfuntKMfgcC9YmL73vBUopv3SBXGpmjc32r7A==", "algid:sign:RSA:message-PKCS1v15:SHA256": "F3OeO7Dz9jes3ny8+lFGHEVnPgVORtjtdi6/VEU+tENT8rRzvSLmobrYHwWTQoxfnN40vx8YSGcLesZ4evsmkCIoXKGK7pdKFdTsyBZ27wgzv6DTNaQ83arGmkawo8tY6NuV7FFuwg3T7r3pK3uZFVp6rMhU+IMBnaHauqFqkRMV/E40hF9dXkkUiyd+RORbOoQfUnm+Aj+fJhm3I1X0oiGhGmEbvbWNlSL+gFii3jen8IY4zMdWRH0b2yjPH76dYfQp5ziD+riGVmtMDCYaeItxzespyLMoy76O6W3ln/GIJS7F+Ur58/W2KGaYFBBiO29XQig0nNCpduv1cFWreA==", "algid:sign:RSA:message-PKCS1v15:SHA384": "DhZLYXU9TlyzK3Z/9VeBXlOsAU/M1s3p3HFMYEq2d3ATDbruODfgfH5+pCcWOmtx/10t8oVCWvK99lzva01C44zp8GfizDnvLaeeGDYdIafHMWFgv5daHfyhhC6j9fUYjTGxINHR17FKr9FNKS69KQZa8U89HgSuChXTqeKXE5rhTdwLo4LvJzywQQzFxB+BnUAW5lYhh6RwFxQ5bwWkB0Tw4wb2x35yXuPRRNZ7ZEqg7a+FVY+3MLJlpYGsUncJo61O/OUiL4+DaK6N0pLrhE1vlITu6xQQacJzsnVfHKKbwmcsCW/tEkKrkDEQRB+evEkfySnj7tKvrRCp8138aA==", "algid:sign:RSA:message-PKCS1v15:SHA512": "Wwn8yGygpyV3vmdNVrO7DalkBKCjmrf4qvJqpBeSkpsfyEM8/WzSkPPBq3opw/owwqBCZ5eMoJ/jLDmtSFx3x/UuPFSma8ApNeVdYPokhmIFKkjJpKssT2xDsEIRykxx4cS+I26V8/S7ckMrh0wbzVgf84898i77qTVdRvabX4bbc0i+7Zo48dtexGTMDB+Q+RNrp1eWe/ftF28TXl8+smv8OkKpItUTX80XU9Jz9oPtpCbLyvg2nQlcSnumjtN0ViybAo27gjqYUngTUbvvt/K470mBQjMgCE2UPIPd8imJrvzfzi42hi4vkqnr8B75ju31zvds4xClioSw0pqUkQ==" ] ), "👋": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "mGwY+MlCOee7LwmbzBf8mN30wGoqOORpMngparguNXQ/ZTC2NEvE569YsXBurltZuewBtDUu92j64qJQL5RZj1jf8unc7bmZV/t9wi8Pp7WNivGUELCTbIl59FinzUX9RNnVDzrbeWUCV+el8Dgi5QVO2Imi0IuogFGsuaKOhqRFWjEGShlog/rO2lzW52qOJqD+MLlkah+SGwmeDAtZn9msPRPsDg6vUwdL0WXpBegdb1weJxYrDhQZds2jOWsNMoneeYLsJ91Mvej6g1fwGIuuFqyR+Abwko4FDJr2GkpazuL5i1cKzeDxk7XNl7d5rtV8wuvr9n9SikLJWIA/jw==", "algid:encrypt:RSA:PKCS1": "vdsfQjDQEgDDknqlU5H2a1QSjFVqwBcI7TiN6yEuQfqv9IWsPkh/7stCQupoSsDj2Z05i4DjeN+Wz5AqXHh00FT10P3QCckidxWQjTCQYEyPjVwQz2fZgNhMeKnDnXKSdYw0I9CRzIG6nPcg9SGWBdvDM6T76kHLhvxndKOBcEWOgaJgYRV2J53CSFHqz5WdCAOAybtHS134YtyFxa32EcUI51hjfLdKePO3Zc6Itb7bYIsrjrNpbbjUXgzQaGP5D1cFU1j+m3IONsBKUXyq5UEmajiwNlGYcPaHbanack5rMaXgTTLSrxj42F4ixKwxU6zVYl78id5qZSZtLJSJAw==" ], signedMessage: [ "algid:sign:RSA:raw": "CaOHcMXljUkF0T6+xqNBOMrzTqq9+7WpWkN1QkhOzN9Pn5+2m2y8NYFsdBOjeuWz4TmI8z0n+yDnl7psbTbn4KpXb0tm0HJTW0gcJS3bv2Cqw6+SQ3RTV6JzRBFvQAsZbwnUa0iikwLYlMHWKMFBT3NTIiOouPQN1RNBKm5wqGNFkUTnR/ILFE3hUVW2UdsySSAqvs7SLkWRYEi+WzZsmKv5h4ml5hMEX42I3cqmzkf8bsMQ+qT2sKjmt1bC+F0qbIyjsujDXAWuPnXNIT1AnDT7x+xPQ9dChdynHRqtUan+l8JDgk60oOghQkv1H1hv771yplvJP9J54NaABUBJ7A==", "algid:sign:RSA:digest-PKCS1v15": "fyIf96DhRzHOC7r3JF7heecK5ajv20Atm4MhvT7Ga+ndRbtKLxOTVM5Uek28rfXvxJ8faFfiTTse0Bl+ewsy2WovjulJSzHftWACJiCC+40aUOYgtRNH58OUC4qn2m4UwtRHm2NEMKNdnGRvwzXa57WiSulwzy/QXn4qrVAHnAQl1xHCSEcDUi0fEY+pnGNJQczA7JuL2qN3k5a+66t2KWRKFvnApP7NLVjVL4oHwyRqsLGa7y6Kk087Q+GwrzHNvF0hz7bzhjxjXqpdnexkKeN9u1itMAmIH/RxDnagMgw25o66ZF2L29fJn6zn0a6ZVZEqryKaMlbZ2vMja/ka8Q==", "algid:sign:RSA:digest-PKCS1v15:SHA1": "c2cnpPTRoCJcTEV9BXt5n569Pv6EhA5hiXoRxyJfprriRlTb74nWERz42DawK0n5zAwxGH+UTKDFU74iCT90ZFb7Q/uNR76hPuX6rj0g/H7JltW+V0ITHztNl9V6qeQpT1Dv3BEG7fIscpDXwl/BuyGVvb/xqw3ggMGxWCOlu3kRpWxDP3GsyLbpriw1rWxOuB7+CNXghfN0c1ajiJms/DEr4x7zn1hXybvfBElDQp6D9C21paIF+i9gGIhdajvbz6r9uGOOpEJVf20kG9EAjgpRTUhHAvbNd8G59Di0CS8H6GZRDj7Yth7pS0Nqxeb7p5uu32nOkewlZg+eGJ6hjg==", "algid:sign:RSA:digest-PKCS1v15:SHA224": "B1BqaavjnFBJWwVYWoK36yB6w/k4+VYfG+yjgcyiK8t9fNZY/LJNkvtd1eAZFbUltunuoDafqq0lpava4aWtjwXogzFcQddFTZvZ3UR5+mX4EmTJrLeqnRQf2NH5p0eWqLLMCSxlMlpk4MIxdOY0R6RMW2sfjRaYSr4WVpJPQjw2QlBoNOePs4w0wrRodR65hyFxu7fjoRtXV+Ju+ZdcTZAEEBjT0CohP/unf8czdwbNywvT+bm6DSbjzLeQ0HRKlK3nSM38HplKeob7+jGi8l6oAopAgf7VYdN66tk7mfrgNTzy/dIlCbZFyJ8MnLY8WME4+JSdNInQsqPJaKS6nw==", "algid:sign:RSA:digest-PKCS1v15:SHA256": "m/QSRdR5dPinzrJodgs3+CitudyEu+dMO4ehlORc0+GovBA8vQMcfAy3hGmLcR6fJUh+TnaJjS3Mc5cCcPGPuL3Uam/k7ZkOogO5c8p+J0bj93A+3u+0rk+GjONGfkkR2kgKtFa3anJFMR+XPWHghhGHKqNHwL2X7JvW3hRDSCOhC9gALJ5s/LDkkojxt2lr5I51UL3JQLceKlTs/zey96SK8vGcCASUTzsWhXE5RbTkUqWF/+lnbuRpd96VrsTVsiUNBdYufnPSxQAhG8whZqgxGmOEBdY6ff/Ly3W5K18vF+NfAnLJuvmsLD6xFKTqptiaWpgFEX8KiT2j3b2hWQ==", "algid:sign:RSA:digest-PKCS1v15:SHA384": "T8BHMHkPeA3cyH1/97XReTybYgHYDXxQ443epTi4j6xDXP50R6aNMuqruTu86SaTSSftEtRUp+jvVNFG/b8YZ+wChZxRagoypgiL58MS/WWh0TuIL6guMeu6+U8JlZ7l4XJATrZ1PkIQ5ZmBfAxb7ZfFdS0j9Uz+rlkQXZhWr+0j1IMb8GYdilspf+s7NBdxtG3jppXNmxv6UldKTz/gHy9xLfUyLxLNUms/KxBot8ckLCDK4/iUuZROm3AhHhtl6nkd5V/oRVFT2R36eLvsI/hyuJMH+jRo7j3SxdVdUX3dY7aMaiTgScp/ZvdPnMg6jeVFei98uV140sielQ9aXw==", "algid:sign:RSA:digest-PKCS1v15:SHA512": "L9Vfilde/EPKT0TLqC1HUQdM314IWsNFDEFQsX87NQsNckkoyvc5pmdGwiN8bnEhcEKtv1dRLguZ1QKNt+DPB/gSjyUFrTttbCdkimc0cMHZ299IWpMQ48ouq615RLQU8clXdF8DdxP2RrLDRwR1cQikICVYyWhvVPQWjegemUyyDGDru0arNwOv8SOVgTs9JDKSnyCistbMV2UAUOBiTcL7438XRAnxGnOxsWLzqAdhM7LiGARvYZph3gCF1Esf0DxSuAbZRvcPClAsWqUyoGq3b8eIgGrgXoRHpc5GL3qFtRTK3Qyp/rvGNS4x463J6rqHwiEcy5YUE2ZbG5bkBw==", "algid:sign:RSA:message-PKCS1v15:SHA1": "fI1C2MQN/NXyAkBUpqkv7LdNAnbOp4npAmQXwSxk41yKNwCHTS/kIWGcOp5YQO4oW+J8pKpVULa1N/z5Qyu6cu7rJA80Bl1hrXKwSrKPGJUUPlpsqQjtKpMEIDrjJiEUuicVDxWXIeCSH+M1RJFnq34xe4qKde2CzJQXMHORUb8WPxboqLjRGXkVm7biZWiay8eDT5ye96FOBWwZ/OgvJ0TP5IrhUhvufZ1bHZbpIRYJucGBbBN2jCyvZa76StqnEYxYdde0DgJQp+S39xD54OJoooV5f6KzBq7MFdRaf6ITBi4DW9Dzo6ArannaESM28zLHkMbAS0LMjpunvKEdug==", "algid:sign:RSA:message-PKCS1v15:SHA224": "qEkbcbuxvqAfofKwNZ5V3mxFQvkX5kSAezgMERDilvkY8+dX2NK3v1hzGEdKsSyUpGgtTcLLhXSeWpMHeXZpJp3gUpuLFoeO55eaQZM+08WOf7274wMRI8HfXezutt1MCE68FV4lXHXgnybvYP3D3Uo9RtKvtbI/IxmxNqqptMlWNLZpgyz81MRRKyqlNpjPBCAYfnC3VNa3bw4/tfmxToYBBD7u60QCRKCSivf+CJLtuW4w6l/NnoWIzxK7Uq5yHpr+AbZ6aMMMqoqFvgXm74GtiASgcIesv5VlliHFLsUEehvwxwAfiw7am6WMjV/fYEuptK9xigVD2YZiMCv2Cg==", "algid:sign:RSA:message-PKCS1v15:SHA256": "fhvyoCHHpxdI1sqryomWcGh5li2RChQYrFo1aIprtCIKunX0okvEhx5UajK1zqmMW91sT+5lvES18cpIyCuLsnnqbwF9Mke1eW3Lg/stCMSYMCsXoZETyXzpVhQsEMCj3KXXGrnQ9ZfWp257V1BiBlQBfJjVUoehx4NdMhvt2SRFQZ4+WH7ZY1isZTiCjTiSgVnEx8vHXIJp2bTqargmOXPPsCaGOXqTjbrKJt244C6SOPp2pwQ96WBToRPEujWiGmXBweyBku/RPcoSWeu4Gpn0tHcEbtd23FRhF9nNIAKlKd49Yr59FGohWnNqyKXLvYFNu4O/cwc+SXXQMcrimA==", "algid:sign:RSA:message-PKCS1v15:SHA384": "H0xtEUUQBdCIHpdZ25Iu6V/zuecYvpHxYQ02PC4PFI3cgW7t4TGaD40yWy2I4KQS2b8sLBsIYe65tpp4saUiwPtQxyKcqg7YhYYWOmdn9+OF1W98BID0B/4MhWZMeYDH1Xq1PR4eEPLJZe8qZYPkZyPIIpQkLoTxwoC8zfwceosStdqxZ/QjNTu7hJLnFXKCtkc4vtmVXCFY/OTaG5ZFk7Y/zk6CfvXcGky5/SnXqNOjvD39EHmYbWAX8bHxucntqpY1ZPAr+NReFUJUvF9UA78h29oc3uXYsGoSotJ3z5rQoXzHsKeDM8KLY531l7cXePFuC6Fg0oFG91isXHn3hA==", "algid:sign:RSA:message-PKCS1v15:SHA512": "ddTr+cPSiJV0nMcjP3VlhXyUMIA4tgW9LHhYEZzvDFBVINKrL/eL9ht3UmfgcHg/HMEilJOlRsHpCF7VIHwOejvb7ekSnySWuTX+5KiRgY9z1NmibYwEF/alJLyIHzPoOSDHMcsBUadTh/9CTY8rQXmxsKaENFdd8XfBNWw0sSLackcgH1+pgg+2fx3xTbYwuFrcfJzIkKQpCDV9CMaNsh7BngHJ1qVADZESrxRqwuJ56L+aMMTag9SdPGjdHambJX/yZbjEtE5JcDGu21IUvrcF/0hnmnzRsmwiO/PK3m8Ek1surYr8Ohzssh50FLtASOEz6gXQQpMYO6z3He/dAA==" ] ), "RSA Keys": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "bbxatm6qJob0II7nkk9XxOJjtJ46vNx+sraHGOo6i0oUbi5+iZT1kyVRnm/RLir654RVkTFT04194uSN0iDnbfPJDhrwh9m1uHaH0XMAxWStRhCMYJSIuk5YGSupjuNvzcbngTK5O8uEWWiVNJi/UmYUEtIn73FN9h8NbvJkjN90o+Qyb4Dnp8cutZDNoz3NvVufvt28Y+w7FR+i186lZ6S2efzoeHK/h7DHPrs2IQg1UxUP9CM53IeUvG23CXZdC8M2N8gNIcwRk9b5RNY4QK/AX+qr1lc1D+VfhiTYiICzedKfoyNZFmYkiJZiFQ6hK/QsmNkUAzgr6Qe0T4oI8w==", "algid:encrypt:RSA:PKCS1": "RNk3JqS/irwF7LuAO4xNqAzPxzAksnzNsT5QioIGrMzThAhcvhArjHgJZMC4bBVrL66y1fYnNhogRNgvOWc5CUz+kfTQz7EbzgnEAgeDRSrB+MEHes2CTdGYoHNXLv4bSpY7y/bMZVX2ouhIvESYASdyJb+BaWRs5heOum1E5Je5hz34P7PlKiiLzoGRP0b3du7dbk3xWjId+g4kG5TRIa23tuirovz5nITWiAzNTef8TwcJuwYF6QRUn4Tyhx308VvqV3kKHTEU237TL7NUTY2shlv5F/hnA9u1KfvkTc9vfp7HZjTF/ufxNOZ/PTF8DO9OTbjGMNkGnag8bldPGA==" ], signedMessage: [ "algid:sign:RSA:raw": "IwhvsO1TLzCORZi0n5Kebw2AOZybVYZHOC1wO8YiL2dYBHOcBIBTnmaeaHMn29cyfPB2POsoR7NYSZnpFK7Z4ikojQKOJANr/RoOPjJMHbF1QvuS0vzSbR11wC/qKAqqolfKzvVsML1Gacy++loAPiDN9ZknHDbTywU+1yeDM/8SwZlkO+kfwKgxjZEsffkbx2FMn95SJVNVqxGZKgXJexu4il8qvNzSyp94hkXzMyCSLS+DOxrLu1cwxesow/+clpw5kaBfmPFRr2dMN+ZJgHaK2ShaE30YpGVojWqUHKx5I9xogX9t9/ybEICziP3iA/tKybPA5AOnxbuGPvUZjw==", "algid:sign:RSA:digest-PKCS1v15": "IqXz73PgySx0TcBvqT7fnc1Db/v+mAza7pKXEaqb8GVvZXc+X1B7iQ0o9WJ1KQ4m/zq8iAmDsy9B64eOV48mytrEbvV+Z/8M14oGd/GbbjIsWxGF2ksS0deC1j6uBFdFiuYptBSecMOmh8VBDFEvkMSvHvUVbssn29T+wZIkx1XR3wMGYnyZ8kBqShFPGWoSP/BElv7ZKIWqBox5qVMFQJ5WdKTAtp8296gg0CSwmRVayFJQk6hYSd6yj9ON2X3QGgaIYXTgMrkl3A5jTTtydBawWKZkdgWcGX468Kc+XOJG2lNN41Vv80ylXtbYr4wHxx0q5MDp9EB2TfLmGxcbtQ==", "algid:sign:RSA:digest-PKCS1v15:SHA1": "J/1XWvnJjeKEojtDBX0nwFJNVh0ONp2GNta9HaaNBmzOxLDg1B6Ejz94NBwKQDWsZobRDU9YRJa7uv0QTucWvRW+30dKRk8B3FFLzofW8wjJ6aYPN4WH8pCHcVpFEgLXj+i0Ic+3ZwLXmxRdFUkR5xm6yw5H97HgRH42fu+Nx49z28ax7x6RTwpN8nTUxpJd0b1uQsxmMUcYut9l2+B5xuOqy68HdyRRed7O9BK3tKaXOiJ41tYN2VQPmpBrg8mgPEK3jXTw0PRZDXknt7tOR+RetkLoTw/vyJg68hO/BI/R2W8IkdiYJcSvJuflKIpixthAQSxXtC1bPwfzsnoHzw==", "algid:sign:RSA:digest-PKCS1v15:SHA224": "l2twE1EC+epUT1n2Q5Vh9BN7OicgBhJIojm5mN++L7RM9ffpj+y64s36WF36ga2LwDhr9cI36BKyaSAVffuEhOyQP41pmJD5/Kzkabgnn0mbHY3hxCbGbGVNt756rZVEn5cKE5flduJN6F7NemTa2QLitxZjpcbnK040LF6rETddCeLEy/VyLkhHsPMPrwNV7kMObtyMZZSy0iuSXvJa1EyfPS8MWAtPaHA7jMKCcrBYNgNyu83S/EcjZMI32CkIXR/9RleREF+sjs3Dqw4f5CdlKE6uOsABnxs4c4f1Fw0FyvWUUXABth19hjvSBK90dL1rPGJemTReqDy838SQ/A==", "algid:sign:RSA:digest-PKCS1v15:SHA256": "jvwFWBg7TITy16V2c42CWW87vPhatuCCskeYmkrMimB7pg+QX279cNYaHdjiFepdiOc965KrzzyJtWjq9yQByPkPA/ht28Wu3DVtGOyKFAMb3e9/nyCSbyyOdmww8Jl4fSBm1PxsRZCnXFXPSgEOZxQsIgmvNPq940mnnQx9Gmm/MPNlX1esgz8l0blfsKv6iqCRypTUcalFshfaoyyuy5BXzvtShJq/aTiT/UrmHFpCs7B58SfI8M2X2WInz2OW4Dwu/0solFb0UBRxeZzJFkGn80fejrDGjM8uSFYs83s7q4qDkfsG6mguoRH/QmVkk5EqUy7atiO9cbc8ua0g+g==", "algid:sign:RSA:digest-PKCS1v15:SHA384": "q/nfxJuf9aT6+fidZfw73k4h0h3Uy0aE1nnhKTQx8eFKbM4pAek38Xb96vCXWKroBbNkjETL1Wnhoe6pN+mnZIVzrL78V7jvztvt/kUJR2wpDjbtlJ6DqseesI8NtxQrKV8KHL3jze24wts9pgtXJZXuP701hQDybCwErEhg3FTBFlGHRc6ZPHQTAs58uc7AvX3x5+FVTpktZm3e0EcTC2o0zhbYymrn8qqU9+IdQEW/MWMDGvG/Nws/AtqTkCJroZ1tuNN8ZHq1hvZLkJfzyK0M6B4BCJvclBAmlthir2H0zb1mvzMJURBZwXvigiQlPmtiYJ+eZ2LU8dC79EFyyQ==", "algid:sign:RSA:digest-PKCS1v15:SHA512": "kWyisxyJcUa9GpXukWKWv7HY3oGbkOt5NrfiiaSVJAIK5qYVF1IWnTsd375mCOqmuUL2jyrYJRLatKzMPhdrmNdoWvOcyt4Dcr5rMtHviREAAfCc+saR7eRmW7YNl0q3LTZapnqrJ+TdM/dKN5G9YK5t8jtb+rvB5iQkHPxrUd1mjbqUoYZggMSHJ+Hw04cSsd1Eohy9ZLclyVqc885aLpkftN6pqX/pNtMTpBexE5TTtyyr44C9rwxpc8ldRNVSYHoKd/BWqouVPO54MMZNiA7yNnXC+Koyu+8AatWzbl1R5vlCWiC7FJYW6T80DFFLproAsWh7dNw2buBH5qozVA==", "algid:sign:RSA:message-PKCS1v15:SHA1": "QxbPM8B4mgNeO3lCTvPZ27WQwf0oIY0qjmj8l8CAK9g5VkMqjKWuW18sEgwIcaBfQOsZTJhF88sDJ2bM0DKRsmyQzbN2ogct9ADiIUYTp0osazb1uufsy7pQC+Nm2Ui/uGvb8lyYKQ2Nsd9TfBRx8hKlO9uTvcaN9jAk5ZF1etUzfN4p3DbQletPXJVKQgWOWkXD8U4F9BTHVK7IFqZ2bLkeCGppJfG+I8iYqz9D0r4SoojXsd3QvNBu8DeWR/6rrCyic53ct1K+fnrRb4oQZvREG/76oaqRALAyOKxDBQLvzuGyoSVxWfcBRMTub+dNVnvGFPADj7WF5LAgWqtGLg==", "algid:sign:RSA:message-PKCS1v15:SHA224": "23yJJ0u0uFGL7uj4NrQundvvktuFgbmi9A8s8dFmSeZB9hzp6FSQYd/CKFYWYX477UCM9IJx02knhQbkYyGmQf/Ei/QIPkdLxrKmfobpgzUez0HFrVEUe3I4jLuffdg2vAqk14WATfTbJXIX/3QTUDgVDnsCfFZEWAE2OG4GMFocTr56GesBSZp6V2WwQ2tWbsrGiv49ADKAb0vCWvTGBZiiG3j34d3tHKubkICJ3bcOWWerwXrwO+8PRSe34lDc4CbUngq0JeIDlb3fVEUuvUe1Lq51G/bj9YS+nIwFzaE1YJUxF8iCmVeFPo8pgMIOCqfYkQ8tWVC5t4R4jCdz1Q==", "algid:sign:RSA:message-PKCS1v15:SHA256": "FmBav3noN6KHfADGmCo+PRNXKzLkRGTmH8iLwEAXxGLqhX31fbN1Hnl2+TgjJLaTWmDmHY16jrpPwtZHETva71cXmDGKKfsMXEtSyz5XS+DSZKHQsokS1/JNyOzIPdJvFORHoWzyc128MODvjBMWU23nTLmgw3cogYAm5/hc+527yg4Ydftr77zSXoXBbO3r1oyTv3qL7FwOui+RpfH+sQ6Y9aGM1EUWqIXkKTfu1SfrAXIiu1J6vdoTLy8XTQrPcIQFa15/KMCUEte9Jh7XHzdWwNncqWqiqHoSt375hrDopMej94/rbqrOtHXo0D+sbyJCpSDPRckMkGDFGkQ5QQ==", "algid:sign:RSA:message-PKCS1v15:SHA384": "2hWqGdpkFGynqvRJqRu5LPUjb2/X0ZRIcfz7nww5n9N8hbqhXs1SVbz3DNaPKYVHJCGsKs+TNvgHIBWPbveTuR1w4mxHTpx3DUufngLZuwNBfm6gizjwC9QxzHin3n5lLJ1TCEZWJIv+vb+c/lcqXStjUHHWr6WQPtJ9z+3i+O2biW/Y6kNt4TeVXZ8X61RVSb4F3BurYVt9KCuULcMVOsOVbHgukUrBszm6TeUm0DmhEBr7kaZZeSTOSqFmdUhupB+J5zqIxBGlQGaCxXRMUr8YVktewiwmf4QU9oOU8/aok5hq0RsdNtqXcBOXHUtmOcBdzN4fZhuWN0K7uubcIg==", "algid:sign:RSA:message-PKCS1v15:SHA512": "kJ+yZMsLHDOlNCxQVd3iFgkzX5CewVhhSUpBziZW8CmYEncLaDF1bWpOPGt3ItMtsgHD+rpODAMnmtm3ESFYjJPOho77nLavNPDTmpDZwpVe+guO0GAErAjz8NnNcExLTcSM2kLFBx0eY8N5iLqBosUvJP5R/3vClWN7swE9b/tNyvMIEz0BMOUrA6y1YfHZdqrehs3O0P3jnOlO+Cah2QDx3DkVVjXxy7pZSHzkVJ0X270q9fGcXGfYO4wLRe4asZ7R5d+hMBCLPewjEi0lZdhyYk++jFBXRpKkxTXLKWEl+j3mwKYP0RO20CIG7M+jYqaijMwsGkpQhoX7Bigk4A==" ] ), "CryptoSwift RSA Keys!": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "AP0oc4v21hwhV2XRWA3bNYMZiADeggp/eOaLgeHnMq5iskk2V+VqT3tiA+ezRlH8Tu1IivAxD3xC8nPmqzK8knWa3MeDu9u6VgxxKgl6vzkqrKQ97Rly1+qcNSdMkwLFylS1sa3uhHLq38MrvSdk/eA1ieI32eOzvKcRxGjgKPx5FMgtKZ9pmDVlAjRSxk8JSfzX+HcdhjoDClzaq+pzUaSRnrMMuGncrEsZFn1A1ZbjYLXXKDPpyz94kQsmlpltq+FcB5Pqru2oNhGdrdKHuM921cW7oPJBwGtuOeqWx3JBmZ35NTJiWdWd0BEUAHnuxPZT7+eG5cg0NkugRImxbg==", "algid:encrypt:RSA:PKCS1": "LSPSLZbiMdve6f5y8JNoKCt+oXwmZBUN6hniDS6XwIDnVJ5uHxtFKuCOzJsnpuXmR02HesVWmOT2i9AT7DTgGX2FWcE9J6Li+Uf08YFjgUDVJ6DkvfZvD/Nm+AVULmu3DxjlNP+tjBOrKukGJP+NzLourAjfEls+H4hLVyaKCPCvsqZ14K+RCGHj60YE5Hx4vWXIpI2d0x7FR6C56RFaQp1xD4LCxGy/aRSBE02xEQVd5AmyJ77xmT9p+F12x9SNOf5VHdYNRT+8O59SMDV+zqWJJq5p/fjZKBsQKoEAoh1tJq9XlNqO/+EJNAF0okqHozXiaICI82E/lu8OOS7sgg==" ], signedMessage: [ "algid:sign:RSA:raw": "w+O0E1zVIWerFfUawKJYak7WEkN6yhFa1uhplc+fLhjemZSIyzzd2mYoAhOl0qUHCCn3j0caqr0mny4wvkeXOSsJ3jH1XyANaiW/OAwmWGhSqUtldnW1PbR2sVnomkTR7LoVC2t126/P6bL8CcWj7knq1SJKjeQX02opRNQpYcWhYQT3/JfxMP7+Q7U33NA6MFGoZHkHNrt84/1jWtJV5gjA2Tbc8sM6Jgc2NjZiX16G9U2g9Idz+D10iWyrC1VHVjmzOEHeUGsBc706AGkrfo4B3GrdW//03YBzRYSZAzjFs0Wm0szKGmvWPItthZBDnjC92DYlatAZRprCNnkZuw==", "algid:sign:RSA:digest-PKCS1v15": "o/pbYAxH/4KEhBA1AtIGhm6/momDLNqQ+2PLTEP+9hx0VbS4lKpinEpoEdSM0RmAAN8IeycbsQjx1O2pSmDwyTY5PEBXJ65Q4rAYuI8Chn2RNu+2HRnBZbP8l4DAFKle3vka4wJ0zmLCk1MAuDgleKSL/mcFIHR6GNweOjGzq5rhf9pKDeBeoI6uljg/9N15Sl49gto/q5Hx0FtmuR9MlIfhdLW9nC9qR+8NXapgXrbPFLFttr1Lts3feynssnVAHNGsGFegt9/1BYhVgt1e9KBBpktibYBLbU82YkCMbgtSEK4WAkHmJWM9MHzHbzgpX7VafBRSF3CI7Q3Pbw9gjA==", "algid:sign:RSA:digest-PKCS1v15:SHA1": "", "algid:sign:RSA:digest-PKCS1v15:SHA224": "PTiz3mSJmMWmlUfvcrCITrEfZPcDWip50wLLNs+ju6w54/m+dONfjz4Bd3P1RpmixwXi1n67xKFjXCkcxcMbph62ywAFLrPG+p6kBVrEHKj6Aqmcv2uao5QquETYW5YJUTGAf0T3v5bjGvRW/sn+BqHpEYdYzS6M36awApgsOXyVkz7GL+8EEaP65b87YCZSOWDSTqpUcg77fOogBIWmZsdw0V2v5Dg/MazfKiqD+l1Zvic8z00BjxLi4O9SN4OJ1ObnMvRA1iKtaP4HHvyErRYhIC6iS/SjJErnCTdMpnPHbQRJVJriZ8CKtJTsMBcuwOKlQ2N6UGqj+MwSydzoaw==", "algid:sign:RSA:digest-PKCS1v15:SHA256": "Kk+o0qh5GU7pOjL0NxaCxfqIlSQBhr7OjVzjLEbIOWz3Ue4yMzu4fO6Rp7V3CRIy5Xm6VSZHjdt0P443Cvmeuo28djXWPSimXMOZ2AFo4K/G9mM2T+8wXM+NYiRLSpgns8IPSoLmDUTDoCFm1JE6drLVgBwF0YdkQkGY6XPExeylIzrglQ0890fX8oULms2cD64D8nFijfIk9+L7UJwF3JUQ5jZ27rHOdoTLZymtwY2xxwURBZ+9SLO4gu0EGrZMoSLm0nc+9XSmMd63LekYj4zalUTrFZq6wIMPHMGdIG4fFLrznZijGbynsJwReYciX740u3vlhnx3nE6XjNulVg==", "algid:sign:RSA:digest-PKCS1v15:SHA384": "Y1ICzwp8xr6JVIFvmmbeBIucD19tzDwuj6QaYfxo3AVQY6zIpAHT3WUcL1fQRrfYhxHzXqcmi6J/d2J5LCisL6Hd2q5HkXTO6+N6yrjOuSwvwgNta1X7jvCaYC1qvRqdfO/0xAYVTzwUXHYvNFp5Bvvob/nwsL9EPrxG66hFfXURXwg4N7IPF0Oa+bDG0/+Jl221xsyrkkamByWOwNgWd4rbcrWUpTy0HxwzA78iPivAmb1Pa+xIsqt2ARETluDzsNLvqdEk2u5gdQamQKb2nG/BSQdHcjQx8U8dk/we6xelaOfLFVdWlWSExo+aWtDKgFyactUiRqSwN51ua5m8tw==", "algid:sign:RSA:digest-PKCS1v15:SHA512": "dHP6KJOoT7Ig7i9WVhpS4BhL1fzC8dCVY58dVAPqwBQVEu9d8dbTz0LBvewdD/xux3xY01tvKErEO43S9ZCWUCWWnYL7vOo6/PShBl8J6zu8yK2ngSMRERmY/feIpT/1V9g8vx/ATh/CYYwtE9pYyZR9N7OpJ592Zf3CrnGduSPO+fEtWY0KCJBOYUIb5jct8ZQ4YTqebk1aYX2DS3BFvpcY6K6gM2/VfAbAKFlDRU+oXbqFOZsSUy3SUdf6kdosEfX48D03fBPGrzh2ljj068hgMX3qg3MS1XvhD5tzs4FoxT0Xzvr8WzXrNoSdtGS/4LHlSoXserjimBWoW4HF2g==", "algid:sign:RSA:message-PKCS1v15:SHA1": "sB77+E7wJZGvc2/cLrGP2v7c1b+RSe/TCpyiYEfskg284ysKPwxPHGUl3Dr4zjrgk5kRN9byJ/4+zMinXW3a+Ri1GKyGaa24gp6RRdHSHbK0dar/jdhKl7BEK0i/IeBKppD8CLaVXhmC3rnf1xq7SO3hYcPGtpAJr8RRufzvbM8QCaNxRGyzDQofGs9MKmL33iA72ldGSund0DS6Ds73iGgTPJDL6IkiHTN3awshIMa4pw2ZVLgElGZs3nlXF3R7ok+y2N7e4XsACLedES2Hhc6AlxFMfLJqRz0r/4rt12IRFXg11sq7NZt03G9866r8AqaByR90u8ve+F4s9JB8BQ==", "algid:sign:RSA:message-PKCS1v15:SHA224": "J9yYPlaymi8DwpKp/4GOW+8k7BwS/+FqL3aUB5TwMCrWwCTw6KdSM/Iw0murykqWw3QW+ZsYeE65pmX2fw7EjZVDveZZrMAODMn+qas/mqkk2dXfzAmX8WYHZuGNa3nP+Zljd+FatrQbHI1C9pAJHW/lRsmhGS3KgPRFRdeJXbHQomJNJHKpyZCkFuY2MS4uCzUaGyIF481SV6W0msg0O22mos/cZ7RYD+Dra131yWOucvbOY0INHHj6iRvUn9H7i1jGMXxSACl/MKi34aLgSWKBWzj8A5jbZAtXD19BAURxIXT7X5sAiQYmOlx6Vy4Lxg/8gf8Pc2w4wl071CTCug==", "algid:sign:RSA:message-PKCS1v15:SHA256": "HJqncQ3D3IsfN1GhntgDmGIx58VOD5sY+kF/FT21NDmzZ2sZ1Rji+LTIIRVI3n6pOVVTO7tw+p5hZOKwvL5nzU3qIL20zqD8VnBcMGJrEI71t0QAEgF/fWu0K6clX52AoQ9vS9dw0oKVQeS4MIlbxy85cw2yAxTLBseAzcNWhXmnQcWAU8lhPv+nAcvKkAjkiZfrn3oHMaBMMBn6A2g/HzGlYfOv6L8wtmLR3h4hLy3gxxyR/GOyn6QCKzIf6aygi6/WEz6V4LHDJelsHLZlQeT49xzasebh6hSIF9+2/WiaR7SBMGJqIhqtHLmCuYIyO6vPnh3D8BYmFstHA7/TWw==", "algid:sign:RSA:message-PKCS1v15:SHA384": "RumM6BMqNnf2523vugTgajXZvaqvVTMfCAWWj2PxjytjHxihBb6D2hOcEKKEDDhlRr2g5mfrXFWe1GjANnad2Y814vDlUhFHFcXRezPWwIo8XSPSmmq9VfvcWQ3V3RCxmoFUI+twQJY36X68TgTMcvge0SRKQKfhHMTXDRwuyyWFLxmSuzjwAp8HcKPDUqZN3sChPc5DVDaC4+5TL0lBg/dPXHjS150An2hsUQgpdhd1LC+WMcjFnOsAwPZr9vGW9043RhaSkJwahyckhWUANIwfD2PRVAp7KjiQ9x6JQXZ708nCwRuaVx6uuJbdENOLIEtibtBYWtX+e8znH1Q4Gw==", "algid:sign:RSA:message-PKCS1v15:SHA512": "sOG110ohuLu+UnUTXoEtzAWAgoZBZPzaGX2Ercp+niA8QP7jf7Z/Aus6lVrvvwQTsXPiFbw+CSdyEUc7s2miWcNuMjN+kDSEKPSLVJHv+E1XoIZycVAS80Uiswj7t2id4gzwXvvW6jiJqbN7B+pRXsnUjndqnwzoDcmB9Hte8fIdwvQKNpCbfXXXRuDWMme8x+aqv6QYdnTV3LU6+cgk8ks/M7vtzNVzaT6swK8ppcxcskaHEJmN5MoSM4nE7ay/g7QJ3v3A4hSWPnqQ92bcTbySR4khizidoCLYiLXt5oVOOn19fZz4TD9WeWOQ7HKUSWCZtb9AN0KsLsxFFh7nuQ==" ] ), "CryptoSwift RSA Keys are really cool! They support encrypting / decrypting messages, signing and verifying signed messages, and importing and exporting encrypted keys for use between sessions 🔐": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "hGRauMzAod3Nd0EEtNZZ+xRo3PQI31KaK8xhDSu40NWaHp0DexelsuNmT7jQKL4ZycAKNcsdTPptxl5ej07YE5/kcBybwF64XNU2Q1mDYPPHjoEX/9Z6vihEtH82oInwg/j/7nnkW3P/CNPhV8d/LYyN2maGR/7Vjj5O859DLK20dlM1IzJ9yJXyP/5/00ziBl9MSkW56uslOhNRlLojkYtb1obt1VRhyM0U3G94shQo0kqMrz/8g7O9Tr1edpY/Hx1RLO96I5V8L2cbdHyw49vwCGqaXemb2xvdZspJGwUmAUhGboCMnWiNNytUB/HchWesdNurMw+55mvWGXa/tQ==", "algid:encrypt:RSA:PKCS1": "X+pNC+F/PtjzHu1coJlKSs3TGf4N4bZEpj5MT2jZxqGg8pngbFMAlQ5T5+TR29foIhx1yNX1F7rzJrLrUNYlti7MJbkQA+Qskcgn8UfkA6WXmXX5WrKAn3VeKvqYquuP4NH14Nffz6tHV7edwGLBaxbNDNFZdi81BudMyRzcp+NI4ZLJ3XJuPVWvZxiCCcBi2sW7sxlPjJuvLRmXilxJRV5DU/2t7/lmQcZQBd3FWWuBnPfknJcMdyvI0hS9TAmRYd0vjef5VJ470+1odOAhjFl77YgFiWQagL7TEmxVFKdvTFK90raXgRwUlGdUVFD3YxlpFIWeaXAtx1lLRd4srw==" ], signedMessage: [ "algid:sign:RSA:raw": "JpndIhMqiJCi4V9KoWii4Sl7HRLU6XrVyPQO68YmFLXGsRkXg9eR5tAhjZUiAK3spWzqVvoQInK0aGQ2Qgkv9OG1H4buprg0XwHNEdA5MDwiLMJ1131ZG2WtNu/HTA5H5SPCfhhBOh5gBDKZ8Gup+80LrMKnZkyLg5HAHr1SY5aoNhFJDvT3rXDnbRX3Db1WkW05WeCBjKdstqfEnUGpJu1PneyfGapml1jS9QO4wqiO1TGradEbK7WpajToCROfSYd+zH4P/CtkjY6GL3DjeYHd8fPv9q7TAL2TteHaVpARkoyyYHqn5ZNqpOZVI9Bm84lp18V+81qfAAbOyZYITA==", "algid:sign:RSA:digest-PKCS1v15": "K5oEqdjid3PDag4Be5aIMZRPn5SPCtdVz014aNaNP6vm+BoKzy4HkhJ62uB2jj08Rc3g3dGQOCciZs8CpWcFRY2IsAtKbNYE6lMm9usAndPTzcxO56T7Mok/uNVfp1Y40TrF2TTG3Fn9j+qE+DuEqpc4mQI+8iLX54JN9b4LxPZEKO4NFNLMSuv3qvMT0aEx6J/bnpMg2Iwx9b4WgDTQwyGWuhs3hcrgJTrfMBa1wkP1Ld8dCF+rWn4jFcOBPooZj/9N4/0wThjvEULC5NxHrGTewHjWbvv7DdBgopwEVN0wcdor6Wvo6IQ4DIgkNHN7cgG6VSlLD0m+X8ghFGOMVQ==", "algid:sign:RSA:digest-PKCS1v15:SHA1": "", "algid:sign:RSA:digest-PKCS1v15:SHA224": "", "algid:sign:RSA:digest-PKCS1v15:SHA256": "", "algid:sign:RSA:digest-PKCS1v15:SHA384": "", "algid:sign:RSA:digest-PKCS1v15:SHA512": "", "algid:sign:RSA:message-PKCS1v15:SHA1": "MOilqXGEWJvTNTslUWQ4CVCBqZC/mPdc0UFI3NLA/E44zcjmY82u/k4ftpZR83L+HjxsxtMfKw7USm4MZUENh54up7tHp/8qU9QwRpL315UNEtJaB333kzxfAfa4Ypv927cM7NDbAdBjsbSzP1gQpflZ+tVTd8C7ZJs65lfFFS8ArjqzSnkPMnHxScvxc1OpbwH/3ro3L6Y0E8OUnZ6Uhlz90R2TwenMsXQF8h/IJd5z+o9NASEDzqeUzgXvU3GlwdsYIWdQAA79cPTO/5YtauJ1CPCtzeRDdeII8tgUJ0vzkNyZuyYLzVgqh3zmp2mz4u7rXCZEBnVhlHvQhSyzWA==", "algid:sign:RSA:message-PKCS1v15:SHA224": "Ynzdvt+Z/i3Rn0snGaG2TN1hdppg6h9h54GwHj3ChcUWyiE4UbXK2bsUZf76AIZrT9MLuzmjTGNPea7qYegrxhdQ6AcF1Q+QrYcQzEDhyf9nAcdzc+I87soOMirDsy8w21JE+9UnryaIzWhGDdAlFHexvDemKPjgIIwbCYJbgxQuHaUIKaDiFL8T4OhPchC9x77pFVB7xYxe8+cXkhvV0Z8m3tdtgvQqUhtWlKodJJotrDRm7tqfnYTVJA+psUV3aHeXN2wJLZD8gPEa5jX7FBFFHQ4nx+qXZtoh1YI5eLm2kFrvZjs6YlWi/yM5/EAmI6gbT/WY8cQdGrKvn52fHg==", "algid:sign:RSA:message-PKCS1v15:SHA256": "E1A3YD5LPZjpJef0Nt33gKAo3N90USLFNXbGbTUDzn9hX3g0/iJBnJGlOmagCdC5VR0EY6jzdeRvEJu7fT9jVNwOVXLd+j1r5cXpiG/YCtNKNB0TizIMrS29bBb1AlzLmjFll0yL+o54EDct8WQYnnK8p3iBRQDlnLsEIemljzuYH2z9C3s17Ir14NFugIHlaThjJtPWoPt1L3xMDzVlMN50CHovRKVLK2OuQFByX4i3PfAeBKCHY2vFfx1B/DGyZZmy6VxLRjIpmVyatsp2kUK4vACpYnIpH3A4X6SY0xBJ2+Ylz6TGgO8DGmHLRM/XTlClbPix7FJxQc9QQgtmuQ==", "algid:sign:RSA:message-PKCS1v15:SHA384": "meCIcSgdL22FnKp5+zT+bjAFPjLH1fRBUfxTdgoU2Q1nLkQWN3aSLZ/881cjlHtvFRJA6PRRgrqruCc7NjYcBAQgQHqM5R83cV2urmi+zX8P6zctETMMtvABKIuAVuWqvcPRRBiYxxINBQOQh3e5WrwEVA1uA6vcfMfHJyC1WDITb1SCwcyCjkGd6Y11RDwMS4HtHy6+Yh84hN0Mp3wsbWXtJfC0+kHeNKs/thLxizoxZlnkqDwTAPEUoCKKbqfp0lx2n1svI/+nXbOlF+F+zdu3kKM77OrUMCx1KfZAtu6oUR6LzY3/zLHQB/t+npg2nfvsvgEHH3F+3QELMO+tZA==", "algid:sign:RSA:message-PKCS1v15:SHA512": "U7MHoSi3DD6HiV3CwWgsRPakHdOU9J4UAcU2V5SQ04yr0LvKSy3MZ052G8aO4o8C8cfLTvrjOY2WPnoFpcx0wx0sEyDIQvu9iMzwcmlEwZ3Z69vvX80tbUeB97wXgeYV/Sk9DWUWX5g4k1yv1WiPatIyp17A+9Zvx5oXPSOcOkmsmxiDGh6a9u4fMTsc0u0FQGi+OPeaJ88gP0My0xeO21tQTExvcBcxZn6jFixS3c818uBBvLEoNToSNVdD4otnPOuu9Qx4oPv5vZ0LRw62IpA+LjbKz0YVYB2T2uI2DmGM9TWO0Jj0zyVtNk/l62fD5r/O5f/v1aRnT0agFa5e1Q==" ] ) ] ) static let RSA_3072 = Fixture( keySize: 3072, publicDER: """ MIIBigKCAYEAuDSLJOL0aFe4tSmCeRaOnab5UMuZlY6rELI5CC4hbjChsxd3WN7F5sklqLBE5TtmAZqRCRzcIh2f8IgYqgY7xDbH2UpWixrnN623bl3IPM5JHEdRaQh51UoitJYvA6M4YBWgo9NwN3rRMpbLJ/5VJ3ICpZWQN7JuxquP+byJnkCkJEtnjgT4iTUrbtyj5JFAyM1wBGu5tS16h3fCebRWlZ/PSmdFyzkQAWkXFRkZ0vI5uO7Y+wP7cjcVYXjj6UF3nIacY9n5jmlrVvF9Po38jKMP5MY4FVudATla6TuBWlNf7QGyQiu+xu+/qyBSYG1IKmK6otsfMXkgFZZYA4SVARgtLYTDa4Rv4aVgNnkPYX+GzBsWXbv644G/782t46xOTGQiiNVPiUnyF+BZk5Sxj6AhWQA1aU8XeVFk9EjxYdueRoKN7cgrGluhCGuMs0YA40bI4j1EpUxR/Nz4vM+LyOC8nqyu0yG1InW4tu0mWVZFzwSccPK8YhdrPHzula7pAgMBAAE= """, privateDER: """ MIIG5AIBAAKCAYEAuDSLJOL0aFe4tSmCeRaOnab5UMuZlY6rELI5CC4hbjChsxd3WN7F5sklqLBE5TtmAZqRCRzcIh2f8IgYqgY7xDbH2UpWixrnN623bl3IPM5JHEdRaQh51UoitJYvA6M4YBWgo9NwN3rRMpbLJ/5VJ3ICpZWQN7JuxquP+byJnkCkJEtnjgT4iTUrbtyj5JFAyM1wBGu5tS16h3fCebRWlZ/PSmdFyzkQAWkXFRkZ0vI5uO7Y+wP7cjcVYXjj6UF3nIacY9n5jmlrVvF9Po38jKMP5MY4FVudATla6TuBWlNf7QGyQiu+xu+/qyBSYG1IKmK6otsfMXkgFZZYA4SVARgtLYTDa4Rv4aVgNnkPYX+GzBsWXbv644G/782t46xOTGQiiNVPiUnyF+BZk5Sxj6AhWQA1aU8XeVFk9EjxYdueRoKN7cgrGluhCGuMs0YA40bI4j1EpUxR/Nz4vM+LyOC8nqyu0yG1InW4tu0mWVZFzwSccPK8YhdrPHzula7pAgMBAAECggGANIG9u/j5hBilLPa1G0EDzAqBfLdcgxYUywCSYzOLEfbI0Nz6hxmRPdTOaEQ+jz0cOY7OktNoKE1bftu8dBKszKR02QpomuRDTkq1Q791yWdfzbDCkvb4i4TDWciJhDbtZe4kSS6HCTl4EjyLkk3cBg9ok7yLTGUPUJAszRoh/Dsezr2zufbOxYWjaMl56jhBSDvPF2OBnxRkneLUS47NM39HPkUrzt7oIg7LppbuFoQ3UfC7ZunerdLnxE4KYT3ol5skBcNcfKd1UI8g+oaZfBJQ8v8J8xqSeYLPws50Pi1n4WkJ+4etVWmZWqtr1Cl+YcGg5/IsxINvuJXfz7YO4qtU/x6efRzG7uKPHFBrYFWonJiGJlxsW2RhvC3jwT6ZXit4i5fyqYZHwHe931nb/Hvp7iNyLFm9i4tI0x/yDl9RyHuFJ7M+tb2E/WX5cBOHY+XJ6eAnz+FJvECuYZZXoE/cC7BWsYKTldWPzOv9nwXIH3y/ilMRhWYugNPAhz+BAoHBAN9ZcRkHyVEmG/vnuqz9OYtt8QjfNmFRE3N9xBIuuZBZbTMj2wfEgJXruuKpJz8D1eR19R+0vj7PrULnS98IeHEbLB6bCj+NQFoTZGDMP8YrOfoGtrHkAy5YvYNuInRedn1kLsXm/XPn/pkBEAfoBiIE0TbDZ4YZ3U03msZrc/Ob3W5kqrrC35jSfbbmSv4ax/Xb/UnM8kKgj5S/Ekb0P3hS1DUSwBDNZLMsSRJML1+/Rf/KT2/z5/JDJEuNGsfCmQKBwQDTIi8MZShqDC4frlk7hnvYeAyn9xv8MrHzgbbpfgOR4MKEywGiLEAGy5p+NTgZmKl+8jPt6jIZWEcmFyZEf6OTXsH1vpNW3lANoJ6Rj2EoZTYVJNlgPu2HPhIGM/65AwMWlynV6uenVBfF3VmzeVEoIUZ8TqRsOCXG9KJBJkgo5yEBmAi7G3ZGkLTFdHHEHr7ctbdjE0qPYoujmWBL/tQ7u020BWtzo35EpwYsG2aCfCNMbVVOr/sBqzHPUWgwUNECgcEApwBuw4OB8S5ooDuN5olVPL8RCkw0kiGYRLPWJq5PS/LB5wo5XR598xuW2qIWWVTZ2wCkL3frBHYunCbsITFpNVFW9O+CgzBv3KpBVOuEB/4MVLouYucVxdLOqXZxRsfXGz0MiCeGfeMLCIa14OOJqmglsyf6wVeXlIQuM4zm31E9Ca01x32syM0i+N5LVqLZvyklw8f9oPoDQfp4hRteVe7BA4oomKerUxma7ZaPma0gfvlb2l7qoMe5XNB+JL2JAoHBALrcr01GHn21KAFMGpevT97naTQjZXZRG+QLcuq2Z8xtY1uKHHj+tvAMtUBsM6mbzq+XB1TTCOIbmmTg6jKH0Ss2G2427Epe2fUlqhHkFzZcVYBjK6yeJTWkPumUjSYLv2j4AsPccohKyfuKC8DnZ2egA7UzGRzamLy8ePo2OnlRDopNl7SZ+pU7r3Juu9265GuMvLEIOt4qdrIlpe+8qvPuszfX8CDZm4CBXtocqh5kZg1XWsAYyovQi3YUc6UHcQKBwGGfMrQyUEEk8oQx0OACjLXoyBlp0imKnSEuUDRBLH9ipoYdMb7NaZ191ZDd759lVEV6Xqnp3jHdasj1UPEBKsugi40Vv7X32MbRvC1Yb//M/u5Hnt3tlVNZo3OP6fNIx101da/4G67r/yREBxwt8OUeuswe3R8ONlkbBsfLIQ0qCRNlT6FyubpL2OWJRko4bXuTmMwRSBRycAAc58HHBU9Uqswr24U5kbpBLqc+N1blC1x2Q3vvoNO4N/b7KxiyLw== """, messages: [ "": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "algid:encrypt:RSA:PKCS1": "" ], signedMessage: [ "algid:sign:RSA:raw": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "algid:sign:RSA:digest-PKCS1v15": "lsJaqJpCxmn4VBwdgxhpstYtKN0QtYiouBa3BinSmQRdoRKi3raNmiit5dbpaoJIay11ZZKp7A2Rl+bdD1TJX8OejCF8I4W2WXHTJI+Dri3DFt93Z6YXTodroJ63wjWFhb7J/36d9wAU4ofXeeA5xzH14yWwE4DUPsShlivORWlHO+JQRSu8qEUZPqe1SRS27aRV61cqGmr+dHeowmgSBZ9n3ZfNqP8vS+x+sLKJNrVXNAeYxaT0U1r9HLLAV5iovFKN6STAM3En9xyTFWCBvDsAjl3gV11KzzjwS6bvefXO898vyrqacpcQc3c7DFBYLKuuQOJVuPr9RJdjArJ/SOE3jUX6fIE9w58Jl8/o+KmdhHPgoeeHnD4I9N29P2Z2ZYVYaRcPMVTL7s45OCkcM6kSDJ50p56B1JVSCgMQaSbB0/l8/wwmdqaHDDDu/2RnTLaJSYPngzvr9CPbgdSwHp5rrFX8afrooU4kqzN6zqpweo4NcZJ4AVxyny5+6OuU", "algid:sign:RSA:digest-PKCS1v15:SHA1": "WeOW8oN5I/xdZcpyoC3ggZxXfcHHCS2zkgAX2Lf2vowwVrqlO+O32qObIbCsVNYSdGkYfgVpeNSoCEix4jbxj2KeDRIaY/HaJSyQaMLLBIWIAz2QEBTuldyNBrPstvnu9A1nC9gb7j3r22Wx8GV6Mn/BLijeV+CtK8R9gut58QY4vCx0CvJKk2k7vk+MU3j0zqT7PLiVxrqjLP2xowPer4kwwd134g9vTqo4v+5q1KhdTbDOCuPWthvZy1/NJeo+yqFB/FS6UL6mZWVNU0EhWUjpWyDzq7UqlOj0EepNwiph9Y0uE7gr5++MCNuJ6YKSls34CpAPu/WL2oqm4yjh8yzEAFSQ+3BdZRKIn49iF0q2J/Kw7+2AiYSlm3VKOP+/he50IvpLyKzooBmyP2Cvde/ZF9W7TMpvZoy17PI2JtiqPeFGvCCc5CpEjI1gk+afTCpwh2WoQfEC41uG0j68XiYOAOdqmAtuKy2FRH1tpk+85etJ4EwKHqtfGLw9w/CD", "algid:sign:RSA:digest-PKCS1v15:SHA224": "qcFTjJBxcs1/g2EM9zkSrcBINvuf0lFLhamCGA+YG4qQ3DSqPBOg69PGiIHD6tK3O1BDV4WHh5ysLaHXo8L4PJyQJBG9zAiCJEQdu9tp3Ug0bX4SfV++SFAYoD/j/ALHoZYptQneu304+sfxNyW/07m0nt9xT6py3gIuHiRQGU9TKz9LG0IGPP8C/riV6g4/60iWIqSJvBzfEaN4a9eICeY0hdQCzmxyiTegkNoaYoQep7f/hZO2OkDeR/xMfwxg8DBpL8JfwTJg9gLTBjR1UoWAUtWIIRJeneLe0jKM9nC6KCYUsB8Y87k10Cab6jCleDirB0oiIveoUFTu1obKZU1MUuAvAh/t0Ld4IuJmo09BSG63QF1m8iPl5oqvGpsVnt491Xvru+btjGMm2smVfnkNdFlZmm7pgydJy5hCn51cu4TMaIRMCUXQVRsGgQK8PDhPmVU2qsfyaGGncVn8QTNO6KPP7n5QXafoUAT9vH3BoaJU2a7NFS/uSKi+hmsJ", "algid:sign:RSA:digest-PKCS1v15:SHA256": "P4mjZeQUn0nydkLFi9ty2Ggzm5vBRT5zh/qCJ9l+BeARAnWC/Ff3HPWevvi8CllQxFZC5ZcI/horUJPYHSgu5zuDvYOvWEKz2uWjW3+BO6HdTTh6qrzgj5SzQM4pwziJcGFHvqGSmYoaC55sfHHEGgpF8P8tSqervGQdC46P2BqLfgEDOJsN6Q/gp7AqrbW4pVvMbE8nUXZvhizc0BfynLu2fte+iR97nVLXjsjjO1ZxQHT7Dzr147SMimK+suRw4gjQCAMM3oRs1ROSITw7DdySb5RIhsWBdxdfwuqvLb3+sp7ot8g4nDtfvOAaRPAUGX5mAglRVNsrkHqg+INV6W+sgD48oxno4UbWxkdw/AMeYDL77pBuKjHPBKjcspxfFsjZbs8ILbgIxiKEKcLtsqjd7TrskOe4ezCzZF7Mno9gIjmaugpnZIWcjoGRrvp3zBevDaYK8aVwH4f6abOnhYuR2asHpiURwEz2oo6HVXRQKW9IJwNmn6FOrdcx+nFn", "algid:sign:RSA:digest-PKCS1v15:SHA384": "BJp9R7mbh7IlBCtl5EsXnPGFdAFrshCWxuV5NXfIePId90Z3vIxrGCOjT+LKPczy2QnPpFx6QjxPAY4eNJ6R94zEe26MWtYN3g6JnClFSjk3sGW1YL6AzPGeLG/IzL1zWabU8Try0tgbA4qvz/hTZk6+cKwcXrAUNFX6fLifyI2rjGtXRAeZojDBXoouBQ9leiywvv91D0Vu7Er9ztD1vS0T1zMTV5IlG1oLWcyyl390F60/As/DWQupVQchb8UU/v/cQ/hm31qu0eDMy8ej+oxwBQq0upz0gH4Tia2IO92ZPgbWoTTwIS0cXGSqZBXjNx1vSp+5mZqqiLUUiW2ddJUViCNeWuHfFKWjAAIK/Eap/CR5sGU8vcBe7gvQ7fZCO7tZAIhfcPQN4Qmu6cydIIR7lteTMJ2vuPQsxFXIIPMR6TU+tb5whMD19Gdo5BCku5McyTP5PlSLFmHfLUdO8X47o2K/iCb6zMdltgbvqoGySipxf+AtC6xJsObIg9Ds", "algid:sign:RSA:digest-PKCS1v15:SHA512": "rw4nagBmC5MSPQx2HrRiNr9VFaqpaZWEgA5Vj4VjcxtklYFxfefjhR4l7cX68LFy1V88+Y9ekqa1jVBgov5P6PSgRt3SDA3s91Nym43cGxMST32FH7QPvFJk+pqxS8B4TpuFOZOGRsoe5J2ayUGc+LxBEmr2HxGt1ALJ/y3aGMWjjLKtuRMSKV7WWR59kLBOOArUllBBFE17vKUbmRll3UwiSMJoT9GvH/qR+YP4aaqJpj6050f1rDgJx3FAFkXregOK3aArTmaIcxQ6Uy17PlNZtPrXt7M6bVAkkf4h3QtYigbEk4qcoH667FqDuxgbgOE6H//ZR0FSdM50Uen5TJwsmTdDLfqSOGyWqbtNnm8UY+VYfIL6u9GTTjhaN9QG1lxhKw1L1zCbdQPpybM2N19C9OTP7YLnlyQmE6IAskzxkj6GMEGYjBG7HOTNwoFmdD528ugEb/h7C/BkRcssbd666jx8hLZjvl/9sqsHJu820t0JjsUOkhA8dZ3uGD43", "algid:sign:RSA:message-PKCS1v15:SHA1": "SbbZ7sLt7h1caCfLKTcI79N1OgivGCOYpwBzrNa5mi2DNqBuSMQ5qwpHmtz2PgygvEyyw7LIR4ZbA8qH/ZBbQbNzJpl6W+Ur2U75w2kCpW+v1+gyKMH71GWvnewkyQ9KE7q3EdbzEsAWpYNKCM2idBlOcTRWWQ21aoGEdwqmv4djRgE89N5strIVR+YQKMto+pfRx5PhmcHhUqpVMFZnTDg4IL2/ZHw/IZexzb9KjSAVvL2TTdlqZCs7AAI6gndrLnsdVunc0aiq1gqApRKC4tI4HVlNG7PeZRMRN0qsfRHvjhNQgXohs6SzXAvsXjOYZG3w+6Z4bDBE75ICXV6x6GpFq9T9GCFivipAXY/eoentkFWat8Hj3pThYsdZ2tp5Qedkq2tUnJj71bFAoukif51y9tM1h841WtxpHn6q16+kwKl+Q1HETCaAx0HDaMsLPvvsSDw3rca3wv5Ha8B3kTuFPdIibtKWaNcEQdPSx95EZWpmJrJWmYYDjCbQOVJu", "algid:sign:RSA:message-PKCS1v15:SHA224": "Q5MJLDAQ13EGWxiHzhFztVJaiE9KAWCtg/zhG1mReLH5PKR9lBWYZdWm5Jn7qHbsMJbyVm9iC5TYsG7jMSCii3UmdTh0vJhmUA0DBFriVENkgCXPJDoHMhvPlPSzA2bExu98eMgQ5261Hy64JHMIb6za8tVnD7q23GyTKwrIkBuO62TC9pbjE6Z9JPoxsAGAXj7NVXxtn9o27SW1BqlMEsvpD2OQ3CbUO8UNyG7qtt38Ke/GThYE27iWSlcWJ1CIMxHLYS376z5hm5ZbWLy9w57d2DHWVBrkTVtW6TCpPP3DZyLAtZkqOV5m3CCr/VMID4lmh0wp3Jfs6lxQdvDJ7gcuL0DOMvXHDSSZ/bG0KA2vxtDaHApIL+MiLh9A9/3jguaSkiZ0/ljOLuoniDEfaZOhjJHf+Ye0Rw3Zu6+EKoYe05jcK5vEB5awyB5rO18ynZ5nH2OwtfU3XD9JA+bvp6SN2vjeelIGBec0TCIX9L10+UJxEYijCIdYgi0NeoWF", "algid:sign:RSA:message-PKCS1v15:SHA256": "Ad6cTE873TG7b+RhcSzHeHlw01T7GD+iY3XOGQ8wwijU1OALSNo2HmjEUEpTwq02PNJ0b430uVAFtSLkVTrvbdB6LvSPAzjJZWSE4g4QGxdE8cqVClwcY/zVm9QmyAu8iOKBS9thJeJYEXD3VYTgjH+gSWlRpNY9bMcQ32KbE8M8tltYX6kdy1ehb6meGK4wUBggU0tWj6M+zE6nIiKN4cfY7wjrJ0xKdVTcR+QlIjV3WZRZXhsVn7y3b0C737W5l3qLDjn3OGRwftFcmxfFIW62YuwoukaPxgWOms57Ogc5EE57vAUzk3mn7rWQGQd1OfEzzrkMfw6ksQ4Lwh34AXbxqOMlvNJGooksdRpqRJq1DUOlsHN9kb9s9U6Y6ZKIzTJ0Pldtf/XnWRErkmm/Q9rorJrF3CtbcNZQqP2O1xEwBZpR18yBtkRACfYFCHbNj45YOx1tfhQUabxeDnMeghfrAmpbGMov+aLGSOxWnTtLzGUGSIzlbQD4Y+VkeM3a", "algid:sign:RSA:message-PKCS1v15:SHA384": "sLYZAtuSKWJAHe1CIOWbB8Qc28LWHq+i2o3egLhcUsZk5myFn8iHlQPpQ6uRN/cv9iDXr+5hAWn423JfjWjTariVEchrVCV+3P8Iv8R3UutGN0L5gbXX3VNgdgTbBJG9DozFyc2lkW+MIPxmprbVKHmFpXkMTWs3SCWlOuzYoRazR9LGrApqLxk7fm5UAn9Z26jACIx3HsiVYQpwZ4g7TiHcGlc++CvFR2chKbDpFVhpzQDuGf4/DeKh9MUFlvUa6YpAacpJKJObq7PoXw9JWpWVRoDshV9h/lV5rrS1nGAxv7bzeg97bFr5aegEQwrIJ810n4VXSX9/ESabQuaOwRMaVdsE0dYrS3Lw4BsvfP8xVzT3Rn0R6hJA1mZTqecas4IsCVALmyOYNgv1GKemBDby+XJQklHrCoqPwIQMDWbaDaVvSlRCUoOIXfD8paIzQwBb3mBqpFXhhqsfRlaWOS0Xyzl5Px/kRByzEDn4kKXOT61+ZmBGTIGpHvD175lX", "algid:sign:RSA:message-PKCS1v15:SHA512": "mP+Rd2JeZkWaMg+L/xZDWGRIvfkoQcSyJzEbsjTx077qJX5qGVSlh1pMfr7TtDqGepL6Eph9BZnbHEvKeFYh82up1TjZ3kYQ814GTbbDbQKFt8su41nzhkLePNI8fXgmO5U0bEPnJF5+DQaouzkBebNn8mfaWNNApDjwfvSFP/JJyDWCifLMJmsaSPg2OuMY4vkLFIh6EEUAyhowdmEGVSi6QRVKcsrFXp/fTMzRENFGSEvkL6kVZ5TksPfmMCr0MdFoFmK1b1Gc8SdJAafk+5S+y+YoGE9hEg9Z9jfSzRvvfmIPo1JifX3NLyKR0sNCZ7WCpQnBwWhTj9BfTVwWLJH6lsXKLzfdBn9lmjwEsBYNOgXpKopAhM+Ve+m9DzRZtu8Yff8tbt351VIqpReDrIXrasgHgqLvXu7zcFEwZUmHjQUlCKZHI4RclJt8clMOK1Vi59JMs3SvEb0VHPSYmHN+leYYQ9CMdwpHQZCyQwgJ02XTgu1agwJk6n+NzPpR" ] ), "👋": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "Fy9PP5WgcEI3dDD4o/JLPszkb04L1DedaA3e4VpNFT02d8KxQOaAbhwmAT+reshqehAoTuIWo9B+LtMFA1DTvoj8ldCxYJzaO1zGMw1577wv99OfFFZFKNhvs5pC9amJe6c2721oKwT61v+KdMRJ7h79yTnIj+2YgLeNYVDyBjJyEByDcAIBpcgBIL3DXfPdAF1/EhZFz/Cu0wMzht/p7FoIajtczIf6t30/1wG5IcyaZ9hS3nlNueiswaYnqzfKleNwgLwBEZMTXSRsYC8SzYs9gPA+/JmNaSKzxSbCIFkhubQoaSVd/KxRBCt/zSPkdCj44WoTTXlyBDN/aEJnhEsu4Zq3RkCzxsdVflhyTY2sGIbxCGozGMDg5k6MDK0Ob4GteD9goRuCSOFAEzioDwXS2Y7bRpH5SSzcSq87RDjEJC+jBTttPEch6Ex317NqLFRD3eVAkZ9qG2Zbh5fBE2jCzbnPOJGed7bG5xeTLJ+VVNfDsXEoyUJHewlTGVWk", "algid:encrypt:RSA:PKCS1": "XYpdB+IsM6B9Qsv/0BKRfQM4ut2V36+M3OTkthKtNyKgKsO0EcDGbX36pm+JFkMSmW1uA06j+v09wdS4bX68m2Ndtn+cYvX5vJ7eEPg+erVYcKB6ecyBUUKMoWbR44uAtH3pzmfpnPMjJ4TnUrX7/OJ8hH/6WsdKQJdDeRWV+Xco0m1G6vHoMRw3RDHsZAhSINo7DbTZvovlyLHpjbrhVthv6RrF9J7svT6KGbtTlMlGo0YMml/NjfMKTyyjNwm5LwGqy9JTyMcbYXgfh7HraAhBvt6211p2aT0Mlex3YGw2lqnvEgNvm73buAQ5+fTH2NexGPtUS8w7Du1Qd4dnoDzruuB4Ds3scooICZoy73JAPQc8pI0VluVtofEnOcDQRj3WqvsdFB187zbL3xFICz5XOrwar3PNOMAj2JrtgrbHcngTZQEJmi5yR53TXY54EXoS09lPA6GrO1sptqXlrzxKYTqHZkN54I1v40O+G35h0YC5cdd4nDCDDgDcI96k" ], signedMessage: [ "algid:sign:RSA:raw": "Q/h1sSTehYA/4fb8EQmhNC/39onLwBBCIKeFwGAWYQ7eIkOS5bfcgo77P49dM/MdwiB9zPKRkIst25sUvlFWj12dd4vIuPnOvru89LgWmYmOvsPHZIXLu3zN+4tcNHST/G0UfRhRQZAGKDhXXDDRFrGs5V3m0jEMoFVBFffTy/d9sDf90Fz/zKYp7NATBDRw5GooeFQfC9mT9fODWVWIWpm9gE7rxjw/sEYihTTAILUCDsAqtZU/rknc7RNsm3F4dQRe1ScM03Z3Xvt8WfMLmdAB2K5TS0T3V1VDXUeGK6NZ0BLmEr7q8OZhMbhZyv2hGHYyWpIENBsYqfRuKaDspV913GMoUkfl5HEcivOzRbPOwL0Fd9ZMZjC9GC8jIW9iTXSzgxOMRke32KaGtUY8jxO/6WpSJDQPOWbcEKxl+caLJFsTPNTQD8cIctl6ctU+ZodSC0aBddtGfCulC4KaLniOQEb20z+Mb/rOS/uiYSoPRl5nI8gKjiSEtc2OpAi9", "algid:sign:RSA:digest-PKCS1v15": "G160knrFaIQpVPiVZX7mPSWfTGruTjbjWYdpds7caXMvB5k5IiNNnrrEVdHJw1zC2qhNGEmOEp2wSRoQQSt6wfqruqkFH0OD3AW4UZ0hwFJozjMd6UpDlRsSRb6WJkxMpWuN4QcbCDu12qQDFmEVzp3vy0Fu1YeqG971CYI5kRkBSiTj2uvF2VhEXYGnkMySSObKMobfLCmr+XJpBqZ6YloTRlss3bU7ajMzXR2dx82L7xMDLHTEEbF2Ej8jWPpjP0tKt3deMp3ZrPoNACTNXZlQETPOi9zTCPbv2gD8YNqtCQQnF6xeA3HprWnAS6+IyfRyTnC3q0chWSQhkkGv+sdJjfct1C+u5QOP4IuZYhGVN8yD/FwqCXpTZpZBhZxWqKGl/S206DHibxixxQnhXRRztmDXPz/+Nm7fzDP7gM3kb1F3G+ShYjKbUyzxQhlsgFCSRGK3p2arBgiiegtO8EWz8YqdgftnEh54vPNKkPt/SzZHTmJWPTe/jNLOugWl", "algid:sign:RSA:digest-PKCS1v15:SHA1": "kHQEKVu4wSL/KU9px0pkuuRD84120O6+COZbrvYnRfrlbZiT9sMaVEUJHbYupEmAdH3eLdI+tXy5iJ1D71Lv8k032oJVyVIdjMin5wQhXhuQ2tRaa+E6V7eUV9+cnFpiTZN4PLloe9Tc+xLqFZUTeWrMU77G8sI6XQwsrKKf6FNiqJBClkluESLIs9yzBnO+onTjGnNOKX1QPT470eYLY66b+FrAuh2ny9axa6ob//7G4otiwRbEDgNpjjpWFAkuGPUc8eOIViLZVL/tigweXywDlDhey7uM6i66pvERl5Orpcu8nWhX34ZqHB6OLRv1XUudCU+JKmYSnrqybd752EcJ6/K0cL/jbY2do+jALFSNxBt9QYt1vgU9wMNiuDlNmWtYL7GqdcSiIibrwSPrrwA3yNPw4aHrgHKDr5wLO5kzOIpA5vXSP1v/AnGHWXHe8uxcTCD0nlAg4lNcy/rj5h5bLSqjilR6KyJ+JLT2evxiTjYw4eEZsYvocTBieTIV", "algid:sign:RSA:digest-PKCS1v15:SHA224": "dULCP38bTCAVtwptFuUwcCdBQOcU+wvYYPxD3/TC7CxLcdXZZQNkRU4FqPXYMRnbDpDLy0c0hv8tfVamset1BmyuEQS4Gn6FtV9VcIz1FrdTpoulez0iAsCN/DbXAsc8p4tM+Mbp9ftv5+A0pFMb5IhKJxQnztu8C2ZbR4xV/J5H6D38ulzLG4KnZl+CWmOp8GlVT6mOdYYXbBX4tMfdk+PDbV1+kYExfx0EW0J1rktqcdgOZlyeADiAnyVmb7wKRZ6xxyES35oxzJO2ZjdXDAt/ON7QxeoETf55xW1vbTEEQlcRaaReku4iD5+OdmagLWDgwwq4dpWhwXjAqKzKTcp6zwq7saKUKb9SF3I+rg3C0HmuZFtMC3cg5cA+HAQl0SJQ76yY1wO5ypkrwIIdWgTFjjYG7xTaDJA2xhZ1MEmVN5W5gCH9l5p9iZgXuQVFD2smfcozVL7pUMBR1AcEs5AwXMtVfRkxLbwMlSLtzZSqjW5hcX8d2bWZ7ALnyIC3", "algid:sign:RSA:digest-PKCS1v15:SHA256": "tM7TMQvhywDqO/spQT13VQA5fY1IseTkum6axludNUjmuuWfiRjR1ndjg9rHpdoHxjYQsXQQufIIkbkXzkRsDjkokzoYcHB/vNUs+8wYwaka5Elb2rDzd84PQGaLtbCAYCL/t7DNtC3p+JxZe/Qv7z9V9vcOnqXTmMAHWKUTyluKSQ9a2KHfnESpUEdB331otietaO0xAlU5bSiIfpvwoq6UHUQp9V2Y37sRQG2DX6ns4GW8SH2ZkSbqmg7diETYemth5gtgqLc+40dxF2OkAyxNRX6uncJ3/GccnSwvz/zG1pGB2DNgjuEPr9WgjPnJRRUzL9zBXgVmC3YFUTdNcCBo/Sn0s2qpHR6Ha7iPh2QzZH/KpWmNp/J4XFh+OetSHcT82gFkjpWe+ivHCLNaNnHETfzyu3mzT636X0JTnh9oswMGh6zo5VF6Cp0LevU16i8BAFG5maqsAn0BmxoWM7VH4NdE5QwrdQNFn8dq5l562TTZu7G5Nc0OMqRducbD", "algid:sign:RSA:digest-PKCS1v15:SHA384": "FMbx8I2yGvTZ+VQogpJ/ukXYmHPtCmLEtluLSiWYVsQtCnETQ2e5nBv/h7MXyKvKyhVkR2EJ6Xn2M1ahVXNI/rN9WsaUi+G8dgUc7R9aYMuvouvpQxya0Te+hsdxorYU408YvptMFQXdzp7XKKUq5X1Ra08yB5lLwMzGkE8wZBO/AV0CHR6by9yNl3MB2MnLq7iXiO6jpgLjVuQIImYBvlAXPSvyfE7uEMAZjreG8tj1jTjruloNVK0DAztnolllvhIaTEJO7oMBM/0H0RNZL9sNP/mXs8HUMAvhqEuwq8qLG2k6avRWgfGmPpK7Gm9TWxeP/F7B6gHf+DfzqJNRLHCRt8f0rjcD4RSZ4qu6Q+j+3Jv9KNN3r4Y73/VcL7DHKdsqEMdL67zsDIuSYQh6UCPVWQ8LxzBOP4V4aakEbYXzwSeMyEWMwHG9KaOUPjmfMDPz8Z/TfTI9rDcNWevRQ1InCFCjOKql0P+BtzwX/0GV/tZ5AraIJ3fLxrVdxkfw", "algid:sign:RSA:digest-PKCS1v15:SHA512": "GdRp4dJWKDD7A2KR2Wyl7t0Gi01LG4oKeGKfBBtrrjDg/YSoSec0mMbHHPtnKTqn9pg69T3HtBHQr+F+OEMCshXqUe6+409/YXc8VsC43yHoxSJh2Usz0GyOZuoTccxY76nSqlRLUvpgYqgFeUDOaIE4l3wAHRXgnmiGVBYKCEg/OVeQkDp9RnZhhjIrUAR0ECR2hzv0F0hzmia/ackfDNtYvegQz2IraygQQqs/DtBcNedGdIVD7v36Aw8Z8kA0NYJbnefECNDPaMbHwCB5RiFFpClmwGQ3UWw6BLE0cgU/1Mg+YWmspKx3GQHpmYqQGtfL+jKS7cPER2uCVKY3bxoIeqTs2230avFLBo/FqF1/lUVBReVQwvo8jvmXjZ8OAnSEqw0zARLiVHPrmzzOwVzAFbEakhIvq+UGgkivmEHRFHc5D/ZzP4ktuYlb4pHbyzkljAkgvtj7oAeNuUqY+RZSk/2uztI2gcKy4YkCRo3/BSbNETX1asw0g4uupAVf", "algid:sign:RSA:message-PKCS1v15:SHA1": "qGI7kUhcQC834dEX4FwB0jjELngtdFVnE4Zq+MLmt8aQf5AS8qZKZUU6UYo8dDuDUkhYgO7qZVDiaQoNmYrFzqt8Bm7GUGV/H7UgGmqsR3QUEZnJgysedhCpy5SzlcnYn8y9eVzCQwE88V6tlhxeE1ExV/g7rfxbJp6WS3hNzEfzZ5quRdWTUAtyIdZkqtfYFIcJ4ydV9WWCpePv8PSOA0TioqttkkODLBxfvjsAs+qs3SHl/iy8BP99BV/6M7bPFTmG2kTNEsw8cpF6FNVKSBm84Sel50svp34zBoDuCC4KdDgzF/QVATxxaWT/Ck/QfFe55UKdmQLUylQL8CPIqs9h/5hBNSTnNi/MG3gB5qP01suPRecnKpHyjiht4ZsPspLvUxuGZpsm34THhklZzryTjwZklvq2jBgo4z1WlKeOP9eb4gkOHelJ9LlEgQWtAOdNfybYx1kGbDwxkn9O4M5GycVmJ1qSiULlHaqa9g6Lz1S3Jl5njoLy5b1WPMzU", "algid:sign:RSA:message-PKCS1v15:SHA224": "jHqxfKpOIX/yKLQ3hrMN+ADPdLpkq0BOarl9Od6+8qjnj5oXvVGLJKGQflGSZIEsW/RDuT/ObOnq+mVbdDwI+k2aN733IztgoIE1SRcCfqOj1SAdUL1y4BTempaAQQRyhTs0bPhwNxnOVv50Iz9UaR20LTru6E3xYUQweSGtrADG8C3aR22DK/UKOkFjYLbu5k13zu2rjlVUeGeAh0i6INQSxig70iqcDAwxqxhr7bF/jzx9Kn9k/6L00ynefG66sLLMmU/rOFYe1qpNUnmpWWvZx8XW+qmm6QoONhQ/uyV2hjAcaQmiormjlyy9et3jctN8Je1E8EHAp7VDIagNjn+SD/60CQ489x4ACaNvHRlz9LhM3sg+N3Z2/fPc6CRhT25OV86a33EDdHEXH5kq8zEzL6r7N4s9eiuH9ZMv+5z6Ylmd7bvaPoasW96pYekTG1NWTZOI4vUW36G2lQmm1Qiiqft0NTD8BM4rLMJP6cBvoM2fuQ19vW0biFNUJ+qZ", "algid:sign:RSA:message-PKCS1v15:SHA256": "cS+GgxL982yGQkRB6cm6fxvG1l9tI4egdoPhpCK0OJV/lvBi45uPLCT+pKc2mFB1xZ65gtyFvrtlh0LKMLFuwr0e/RarBvfReaPSieX+X1fNMjUQlgDSv+RDk4Stbb1OPavKACbaCqVMOF8aT5XzmLrOgD7a1QAIU1gI6ERTAiDSxxpHKtoQMIRrd2IDhyMe/kQMiQ99Urdoys1di/8DV4iGU/x7SRcHTqieKPpawVjCwIAHEXy2hsqkMIS4Pp5INb+uVn9nGz4lRRrrPDNsqyiI8FDz+8hcsrzf2J/pdcU4AzQrl46xk4eC6OFgBtPbDL2u01zDbr1NqW9q3+Q75n0N8cUynf6aR/Z+1cGwwvf3Vm16ImgCnTtNm5g6/5q8RxyXexqH5WP0VZzKqjiYpGULawQF6ZNDJYI8RphNqs8bgGnYF7EtiW2GtgjH/BUHe6tcd2viM1ZJJPZ4KlxWAi0j9xhsGw//1j4QdDzRgZFSpzdXL8rMBuupuv6fNnOn", "algid:sign:RSA:message-PKCS1v15:SHA384": "AyV+6+irP/70kPO29NmIyvJskmkdwgSIF081gy2J3qQTSgBzeDaUA0EvLjtDMhcQtP6TBojO2MfNs9Q2WjZMDjUh14Ld/I3Noxjdb+YVaMhdYwoTbF/q+8bmaQDg3Zx1sijxuWpg2cH70wdtbowaK5Vd/GJsUe4SKYTWWvBGlH/nT2/+YaXl9To6z3n9pRrXshH3laADgL0TQS1Ial/V5cNMeNk1iEjoEqCUEayEQa9VmeMgAzLRsvlZuipb8T+hks19DttMactOPGW3UTOUyA/d6WYkQHVQ5ShaxNr3l1PT1Cvlki9JUkgOELXuumH54q1X0WokpDxhBWZBqHXW41M7zfvUm2Cy7Dm6r4Uy1hg9K3qaYozRIyDW3X1HrKT8JugMKPfllBwf1+nvnzdbmbBKY7wSDzCwCQ8OhEzrhYd6/WNaMCsnaopr2k/oy9GT51QO1Ae/NYYu+NT8HTmpOPud/N2cIRaOVOhKigCAbB+1EMgG1tk/AFLCXXzWBZAL", "algid:sign:RSA:message-PKCS1v15:SHA512": "Z+jf0xk0iwOCiddO5U+bM7/kZdOfRYYAWByPJ7w5y8mqvWwF5QQxDHjEU+7wuthPxCYrHWONH7PbmaX/AHGuMOiiJBnoGDezNv2Xovl060fiXBo0lUKzXA3AMVLtYbk/CYMIpBBz9o2Fv2NX8d72drSvpuqfbskTiRZ0zl5qXmYGJikNduGKoehacTPYnwrHyauZ4fclmMluAOR/8fmLFJWj2pclcgmxDkowN0tFwuY5JYbxURhsryHzkpPeOHWo8dUZcAw6cltjm6dHKsRZopVEJuZx0Nv72Ag4hNp6U5Zpjq7ACMqVnhzc5KjB5dFkAf6ht2emQtYIZq+KTvevHdKHvRRy8tfIDD15ZYnpvTcmhHQBI/t/9xFgz5qAo863l3U/4g0DK0AtosNzCx4CQ/Q+oZK9NHavXjleqyc4mgIu/vN+HGgJ0fe7K7FsCW279XT+5WkjgIUTUzDXIKZ4zI+YSGFHJTDnzej7MED5r3dQeYSQ82UpMWJB7N7Ppg+6" ] ), "RSA Keys": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "U72VdQr/mTJpQQGs7buxEnmTG00jJizTCOmLgPbKE86B+Li9+8unTkgN35QJBc3agtZBKb+/VgdzvDXoIvwrGPPKMW+7qX6U92gVxqaASKOcQOW39OBgpVRJMP/NyqWMGSRMT2ZjCofh55j42+1ll029LlqwnOiOv6oZNhQ6OzZKRxja0TfdH9h1MtdUUx/KWRuMDomJ0w8kwnjQ6ZiRh1D0bJ4Tqb/hftCbkF9dJz64ob15tNtlD0HHs9NkoH9QIrg63O+FYL2gna6R1VFI3osvTWk2qhOy/99o7yxUJlxa/Iq5MEa/XjUi/Vv3ZtR/F6LPS4LI1mfVX0wEiN4Eubrvdy9m+zSuSVwkmN3MiqXxvykcgQEI33wOrCpukM+1nexF5xbvJbhjk4f5BC23avwrwd71DSeka5ARS8vajKHoPmtFVa63I/YSpGNXWTzeckqqB1Imv58NgcOF0txCYDYcXO5nMIQ/t1+30JbhzYtZfdY1vLdV0KahVnUBsq92", "algid:encrypt:RSA:PKCS1": "NI29sa5hiL88OyGR/wywdDg0wdRc9ZAGRf/wgeBlV9utdrYd0+P4DV6Xz7IkECWRqb4b/Neb2B+5OWmAK8VdsugWnaG0ZWfCW9Ak5kULQlJZlKRgyKnzW6Mc2uzdw28pux7d87whMGtp/ZloH30onnnljlPu/LNXilZ72c3osnBMhYT8L3GENZuZgNN6mVZ5rJOqx16uP+v8M95sm8mONolAw6ZqZBeMbdsSOnJQVBriw0Rk+5MH7zKC4raum9uHUxvrQ/zhP1bSh+gUnxKsyfNrUjhAdEIZE+0gGOEzylj/xOaO+l9ObDDUbW+GNLN9D4Vge96p+iBGBPqXEZaLKtqTJ1ra3dO7Sw3d+wc4jPRv9OnzTz/agJBgxEdEdRFKH7/HeUtm8Ydfs3zBwISPQ918AkOwzsQYeYh5zkUwS4OMspGrm0xTt8flYBQmPVWp6CKs8OADL5sGJ9qVECxdAhtbpVzDSFn4aWWi6J5JBkNSdFwsHTg9lypiqVTReCbU" ], signedMessage: [ "algid:sign:RSA:raw": "Rh/KvcbbFVG1rn/VohpSyc0QmmMmKYyrNQ9gCGWHJPS7rYKP8y0gCU+JlwsFznrz4XIzn1HuFTErqU8jIxccjTBD/t7//T8v+wQAxpnxVaLja0Od0d+txzFY6VpZkMJV0bs8wUThrLNUOdMfdlb0mZ8uceWYHCzTE5DO4rB5s08XAFWurBjDqn3uauwi0M+R7yNnXnm40bmZlWK/STmKyiYuKR43Jb6fnUykkqX8O2+85URKZkVAL9TzhUUQf5DJQv7gltVihASUiLH/cJrtpi4+oQ9+/Pesim5sTXbgkDl2/syIL+SlR8JNV5HLrpJYoIEhotP1U2ZUaFkiFGMQnR6yOQiVEgral/pjne/BgKWEa1bvfudWKLMcyvkCjw0WNC5qUMiULsdgUXbYh1ZwEUcB66HRWXBPHnYNbzoczdH+75jeCmqYew0EHV1dStD1tN1HdexnHTkoiM3v9x1qFcZnilI/RPTPETbFjf20z8703Za6hVgfrX4S3H8UObOh", "algid:sign:RSA:digest-PKCS1v15": "EebJUans+9JXnl6Vdp6iNFCQUMC49JDRV412nqec06hyoHZt4auo594M405X1ZtIGsCbFRuc/W+L1NL1oH8k/U2z7q3OrR5SkwFngLUfXlfBS6JLpoczSYwIR62hLxbdCEkJwxCpuw2HiAnu8aT2UUg4BFYZiQyXSx6ynO/cTDA0JOpTuK3heZ7EsrpRAQFss3yk19YL+vw8QoZ2C+f8qEzpeVm27dWAZ7IZ1Zre/upgGGWVNsZbms1H1k3Xsbt2WQYgwMrKM/fDU6s3/uxhfI7d5gJq0Koy+qEc8c99EsUKGUm9veBAq3sAWtwDaHYNICN9fEjH8/JuOEFn34X9de2BZD3dWsinKoyGcFjr35RXROYy0ToJmO0Vb4eDC6KLxsMbamm6dc7caeOgxw63ALtvLlsbE28Yo9bTFV8pqJfGWadiwGRvKyBbcUpu/qkLjyeDaTvvXNQxWKl6jxf2QsQinKBRVqSH+Y6AG8aJvTRfSD1TRYxOkEnDzhI4i+4X", "algid:sign:RSA:digest-PKCS1v15:SHA1": "DNhnp3Twvbt/6kqzIMgtmOTUywS229/aJfmlkhta6ZxgL5Zh++5eXw0IK+PA38P+OiToFYD363UoPx0zbzd2kM5Nt0jGKw4bnvhLEuc7QPpwjcg+bGqQmmUcjpi2zI2sYTk8rMljmPrjNGdG8KLpEebpDO2Yqr+bhqWdPhCDIF0FAZNcH86SWo5vsbl2FiT16mD0YFQC241mexKJAS6YZPYpagYq/Sftf7AX5mB0tpBIE7Ga0bwROJZ00Nt7p3b897DYhDNL7XjrJGFSUkIkIHLgGlDyAv0O7QlqX8v+snU935wTCglzp0z1ppC+0avyOeSN32zVqSI5BLmp2GYeuanmH4pEz0n9+ymqDnCRNpAugNprrymM5lWi4UVF1xk7mxPiMUT2yi1PpT0AixsMnzRtd2uyUlls410TzKLO8W564OpxSKohfyonAmC37fbIBEEeEHbpU2QMbxDD9N1t6bOrBfISe4QprI3wBk8m2N4Pn9DUet5390HBR/MSbuNq", "algid:sign:RSA:digest-PKCS1v15:SHA224": "buQOIoJ0Bxro3D4UxrGId+iviipNKznLg09Nyv2vXJoDBC66IXBYI5nJ9g8Hfa7sC+Ou0ZYAmvupkLij66Q0umA5+kP0sRp0xLRJloUsqzqD8Xvqxm/na+XOPDpdygy8LXC5aXE1Qt5MGXXgkVvRMFhOYI6UFj19OpFmidKFX4+MznwgUiVz/k6f+7GQ3xY5jO9WqVSdD6Q3ISY3uM4xDDsUKaYojNTp+Z/3f3TgnqodxeBbA92cWkmmYqTzIZcKMpTSNM+fWYMDoIZvHx+r5jZ2uoXc0YKxr39bBW2SEe6WQF6pQDXLMUzn9hyb0EoOR75FWLYIV4DD+/zw5fYvEE88Fww73LYcXUQuqyMwXheOzJ5hQg5Q7W6OfcObT41zyqCaJujIGLX5Mnme/2kFa22HkvxZTb8dGJRUEoZ0ycIOkl14N9hdUdGhLeO9BrMsDdohL+LbR394JYYbSl2INE5Gl+hqr1j8gnr2fah+UEZ7Sy6uinRt7cX78bsLhe6K", "algid:sign:RSA:digest-PKCS1v15:SHA256": "izRlGRLjnjDPsYmLSfNXzLf+eGKcmw47NcAWlIhit31jyt28klhiOfkMM7thCQJfXsj6UBEEvxKopamuTaatUC3w+9qSVOG1bWXHJ52yCEpmfLueN4Z01ClnLIdm3kRmaYDA3ZRTXM11XSclLpZC07LXT5Bl+M54PxXf7JqmXeNCkmof6AVHop1bD3btLjsApfF7bG3Whsqvfzio69qctrb2MnA5x/yaMQS4CdLYedNNl52RF3oP6TdvlwTEi9O7Nb7XnGt76npFyr85cTwwZ7SsfkWROxLWNo1B4NbzApDieT/XRIH9wmksFvdTq0md5XGk5naBXOHCbKamzC37ehu08EgyHbt9tiHoYvc2p2fuySEWbuhflWBLelzZHD9F7CazjiSPbz7yBbNStv41/FoPFpziGFJgWYZ/0dpdSQ9nhPDmfFlRje2Sd25C3C3tYKO/m2qXF+Bhd6ywbjiHV+cZAxxdKfs0aLAiXOP4zdaVQJUD00At/V6nS3Z7bymR", "algid:sign:RSA:digest-PKCS1v15:SHA384": "Lz7cURi86Mk5brrH79zk7Wcfaz0CF0cJplzW68hMYPJVMaj3IMj81d3ZxHQxbvZzvKEjH4vgCxF1hCU+kXMT2BU3EeEgXLWRa0Ewwje9QB/Xt3h/vxIX+VzrI0F8xybbmJTXADqanybq53PKmovvt2kxYGkNx/F7Lxu8LVP9ofTpwY5imv3Qy6ZM6fm585ywXb8qZBlUHb/6j+EQk8iQ082amgvxDm8FFhX4hdu1YdHD4bCxgYNYDUNgVP2eMHoZqV5eSVWpNr5DApXt5Raom2OP/ElLJ3yNOgCw1UE1P8VQg/xfP/0jBdBI4iSylz7KNjx3lQUVZd+Yl8HqJy37fkXvvvpbJyLBp7RHxhpAfWqRYvUjtQm/6Y34myiEN9BWOqjw3Qb/jvwPsD+AWGSdfFHeS50p58gZZ4/9CYL8MafDJITTymyHLJcZ7aiXuv1/2+gJ/QqNVWBMI7bJRcV9vbEimsO9nXsp9GGmEXut7i891G7PJ+ggLwxq0s21MVpT", "algid:sign:RSA:digest-PKCS1v15:SHA512": "mLdJ7aqJiI5wDOp9kQA22x04uL5uTaaaWLlMybn7zPt1nzyL8xBfNndIk4/dRATgfdF3PxuUqEeZOVQ9txrFG70jkWqNnTYjzkOm1jGtyEYo9ld/huWdUgwYy1AfyPuLANxQM1EdhO/LITESTzq/JBPWPl9kLJVHJz+xqMnweL/5Anq7C5576B1hfWago5NNpB1LLCWHI/KTJ0Toy4eh7jnTeNk01B5ag52Rk/gHP7UZiuBiGHQN3n5/uSG1RwmmryNzFNpQm6W7As5RG/3ke27jbIYfZBs5/a/uXDAze7jZoj1hF565pDo8UFKdWOflteAG8c7GxWSyooLQLanz3uV5UcaINWfOyXZ++sEAtQWJPQ4dIRDRvea65bWIowt8so2t5nTvHSwSNs09wSgtYgtsylxbTsRP2qN1v+q53RsMzeMfk2UffEsL0v7jeE3JC0HsK4vfYEEpj8W1pwHwjZ4lrVAi9GucQ2BxF3TpD+opuEUgwQfOzbF1P9wSChQk", "algid:sign:RSA:message-PKCS1v15:SHA1": "NcZ/8UO+hgqa8ZLK6SBpIfh/XoxoaXn+3rNGzZwhPLYhKjkDyaIZc8aUXdCrCL2BJZOMEvZSL/QDtq01Zit+3ksEDlo7QA6tavdDWYjKdZRk9s0HHXMlW+m1dqsIt/wXZByTiOAm3NgIoppkuhW1jMqiq0EcQzmuXEdLwJ7OaOaLhPv2J+vC0b9y1TwuXQ/eSVCQRAugkFqButpgCXOg5eVeCjqgVJfJMYZTSCTUqdQ/jdscw9TzdszPzOCjy2RMx8z7XQhh+0TJy7cFThAfLJAgA0ePNaxt66zGJl762FfZb30I5K02frX6fDBsAtjTv+U2Wdd5A17ifzAJ7nfhiXb8UJqzPq4Wtz7ftQxoYsyW1JXsgdTxyPJcdQeGGPQ4FT5SKmt8gOuGN2WywtdAurwC+qxVzZU5QDsD7CojcZgdSQ9pEz5DXkfb2TISikYyQ9StGaEDg+ajJ7U5laXD+L+JnSoWa18t5DJMS3MJk+RIXJZuoPsQJmbKLuZ65zmb", "algid:sign:RSA:message-PKCS1v15:SHA224": "O6OOybN73B3uO0rOP0UqAq4yePd6mczA6KvG2RaitN4hjBM2CPXcJFt25tdBx8lE8rHb496uveZ3eiNFG4yG9T/szBnUdneN787Z0b4TBJBFMOekkwn3VXtrJANzqPLPtLqI/Ev32E5p3v35AEICx8iNk34/xzHXvUO5l4dRervCyljZnRIu8yBu5XhYKQR6vVAI7Yq4c7rwu/xF/EhJteQqJ6jD3FTgE4ByEVZuKTkTlUPJw+mZymhGnHhNwkHNEkBQ97vWKINNAWhfH4cnaa/645mWuBug5vziUWwBbfHY16wsM4hZHtg5KkmUvn0dV68xs2T8mcD0jwf+VD1LX2rSS20nzg321ZDwUPmgUq9VkD1f9C8L43a4xqJ7uqamFLAbAj0w9uIyGZQrwyUroThhogdkY5czMVxO8oaDItWDChajFoESHNrP7tIQUwTZIiXHqyQGAfhwnDcB4PFxdz0GSCI5RDqoYytXi2/mZtBHx8S3nLWPENjh4m9ZDytK", "algid:sign:RSA:message-PKCS1v15:SHA256": "QSrniQVuYs+rYvcDpAgmBlyOO0G08hxyJtdk5rmexBhE5wEZUd1zLwsnHWskLz9Zjie0HC/GyuIPgjRPyEoySD8dLrtFjrjtWKq8S0+lTjA1uSw58RdNAATx0KteCxyjpNFXXKs/NP65qHuQNMDob+CAjuXuMysJOpa5Uy23fKHOjLWfR4ioMvntAKfHQp7m3e3pvHq1uTmHstcdrJuPEP22snML+E1W+6Vo57n0DQidCUQ3hmGByvWTr98YYsam6TP2Hn7qTxOnN+ocGVVFAH8ViAnURdpz5dVgWX+keetPh071tfXUQd5fYmjg7IITOzMNl81DrvJmPDSEmVmI9XiiHk1l+JI/bkJOUZmSANoH6UcascUUAtjkHv4a0YwjmwYbIbv0QADs3shvSzFveBrIdmbwbedRTXz0+VXjFuq+pIbXN9oHWowl3JVn/ikIJgHAMP90zttlAE0pJ2bnhN7DcvEfDYnXpG9cK8TrbwQqBfAerTMESc8lQl0aSH/K", "algid:sign:RSA:message-PKCS1v15:SHA384": "b3Y1cyHjXr6zRaTqlnn4xlsKo8pCs4i2I9bWs0TtkzcHeYVk9vsC5Nf9Oa6YRnK1ezW+0cXrdLXB4Se9w2a0c3+j/eWBxcIo2n3P7QGOnOE0U/euNaHSyNOjNkb+ZmcI0NR0+p07p9AetaBpiEB1Bd4Xh2P4wHDaWvkc2hfq21snYTnWgwNc0XasgJSdka43UyX3whmellwNZ+LPpv4MgJ9b0W76tC3dpzZ28Axq6xa6bvek7sP3AfGrr+9J8V+0zrVaUvAgSnLr3nDISuf0iGfh0cntJSE9SLvuWmiOVtEVbcHfIdXtq9cC1z0eWzXfOz6Njt7p6N6H6F/JR7PJH6i2XjTyTwdtraMPwOtQp5QHTIXJoswjLSqcJZ0mSt/4CYNqNkQf/3/p3nAVsF21Kik6V4jonhIDJd/Jqy4+gVmzE9x4K2ayiMTKgyL7Hu68MXRicFlLtd83uVBBik52fudwejVmuary8+zA4Doep3foh0W3ZakIJnOR2USPBGI9", "algid:sign:RSA:message-PKCS1v15:SHA512": "Sj6+dUKsbxxreBjyRMHbxhlP1l/jKIipN9YWBQoxDQJtdkdtGxlYIjB180gunc8wSCWDR2bIXHYT+ch1JM/SDSRuAsGKWeZ6WlsAcubecuUjiKq1s0PAeuKDVgN8f1MRQye1sQh2M4t3sSlM9Kq2Dfzj92yYjf4XEtDBE2NFM1O+RpvGLDQMtomdOfc74R4hMovG7wrNCKmyhJMSRH/mtVsDV8UTiebi09t747SyehXHUzL78vhLEwzkmmpv05B5/FBRuFiwzuoI0J/a/S/L39NatrvHD8shk/jkyYtLKqxFOV4bc/ELU7r4zo9BOFNk7n70BIPv7bf1RYIr+4QF0x1W8y8TG5bQo4h1mD0PmBwL6ppb0WCI/JwBrQaYhyANao+AQNPGKtzT44WpTXKmq/EDwXv+fm54gR7qewqC/WkcqT2fCgYLkfmZZYNkQfikrEEeLCTIn44CeTROSn+KnOBK6E5vnyJqEJVC7Gw+f3OJBjN6mWQuhAoSA12oOsel" ] ), "CryptoSwift RSA Keys!": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "djrMGfalEl01C9fedRjSvlwhRLkcMbgS/uRXdGlnwnBmnlQGCNUx+bBzBKHxkm0lNW5/YWzI5n9xXn3uwGWunwid5/gRvED4aA8khW3Uuxx99v6zfR7h6+oIT1FDNX0zVJNVBA0tC4gFl29uqqCVh8LUHlR8/TkYtl3nGH/niX2JmW2trwmfpfx6cc7AxxAgPaipA9tJiKhQP09Oo6w3iIuoM5691gidhtFi3IVXOrJrS6xG0N8ow8vnycQ24cOPgX8QOC0YjjKg0P3TznNcsqOoSA/3iU4/zapkjXTl6WIUrHGfRktDhnLD4eILCfiwZeDKeZxVol+JCC2Qlpd8qtNJqzS04dt3O0ltmk0aeBeITYHzBP60hzdoQyMUnngXmn1Xu89ASCx+LAji+aTaXGuxq0dpFqSRI5f/W6iJ9Q470xDN1BQdcyFNVRpBx9xq3FCanCaZu4hnTWxU61tqgNUVYnGwNxTWOj2PbYY/p4Tg626W6MANWuzZ8IDMwAnu", "algid:encrypt:RSA:PKCS1": "lmD+QCJjs713PHDvjAPmUP4XrlZTo11qe3l4UCcT4AbjVW8bfHv0X+MFG9obw195bw/3KCkugyod1CTJaIvsrj4Brop4jYtdg/cGl6im29Z4tpZ7N+u9nKPnagAqhTAo7XXguH9/WJFwNbfJqrZ1FgUPJ746L+NGylKtBhYmxkliD2vrJu8kOjEC6Mdi/p5Rr+wWZxWG2KnWbv0bVyhA5HxgP4HhGXu4ZRLmz1ChFQzTh5SENRAzlKUqXc/Ml2pYtqtkbt9DbTDY906lJGQR/VMc28JYNF56Hz5RKma9n3RkH6w336G+T/7mJeit2+K1DpVnjCX2un0hSNPcQ1ZxWoLXTuGpln1yWi4MPWyJKGMZUX4JEcMQvcPWoqjITC8PE77SR5mN6ygzYJOviiu8ltKCjz77D1oWSvH9MjkvSVVJ19oT/VbpiXBGmVR+q9fgUHZ04X00grLq50gXlhDzHXGPWBibgpWfXYSOQFZISBb5W45P1gn11m44G69lpst9" ], signedMessage: [ "algid:sign:RSA:raw": "fGd2UWsA86DOlsOaiqhZMjubf6N/MPEqhjil/s00JkynPCYvqp/46J/6P9UAZQYhye6sBYL5JQJSxlqND1Z1yIMPNAxo27jNQzmI9T5sstk4L6wH3wnjrTwW5qRnLGzVVVpLEOLEJG5oR7vbF7DWXjub8OhPXa/8V5ILfMDgNVu34XzxpvC1Mk37Os6FpV3Z7ytZLzb6WNbtQAbXy+UA27xa2LsKQj+VnuB+/cpwPJnZvs0PT5iB3qd/eW4CjlOCIKJMJMuFQf7fvqOiIxaJmwKLAaGRNndLTvhKo54sW3suCqO8Tfk7i0/tS8Dcn1ojR3KQQK4OhUwqrmxROrY0K5yLrOb0UyB7IiFIXih0fT06MpkPlYW2gYtgkwQ/l6S3cEVN/TNNa2WEqgCREaboD0J/o06vfFcNsYwQLv9UxFc6CnRyF88/J4ySyYU6MPO30hoc+p6nw+8xLrz1mMJElPzn+sRL+LWMv3NFx8AF8gjeALsqk3PBYBSj1a37qnHS", "algid:sign:RSA:digest-PKCS1v15": "RgoqDStvydecqvnTuwlNKfAwb9WWKjEyRVyNVjkiNRDbrOWqCVod2u7a0e7Areb0ZeF42+bcTWF4bHhO2cnLubVKDxXpYGjh06voyCMy4ZU3mn/VAI8h4XkmrcH+2SJBXMNraUlDkuGt/TUdttce7Qofma3Ax3r8+EqQcGNrLtJwUxLrC6sbZdbqyKUhA7j1WswpqLzDa/75IlMNM9qrKevM3SlYtxk3vz5ohr8FP0ltFkVBt9o8JVH9TaCO/djsDNp7weN77Hp+/VeyKny4uZnoFWtMdIDDPEyOle6uSZLopNOFsGCod4jaIFt+Swj12unsaX4NsYlg48K4oVFEyFdzUhHKYCcQli22l4kQpn6GHhI7BPAL5nCvPf58S+DDv927yqYkY+vn1KH22iN6ns+1IcPWNaRvz2K/mg8kl7ZNu0r8tpxic5GE0MAt14Fz444La/Ebq+9ZsxxpLOdo0yLReN2NWQacqb+mzsghw+BYZxWB/sByAaNA7EpbmWVY", "algid:sign:RSA:digest-PKCS1v15:SHA1": "", "algid:sign:RSA:digest-PKCS1v15:SHA224": "fkedPCGJiL9pI8DHi2d99qUyCLT+nh2cSD/BxNXIQgoRyt18Qh6630MxeaXuVUt9HJ1hSyfvVITTRVk3lLGnrWutx0Ot6Rzk7skCqfAJ4b2eu0SYuuY3+xD61y2qlXsDbqM9EM5XOVu8cYrw5O3iGJwbTcV9RPTgFxZly4L92c8oX889LG3FphCV3YueIqbUDcuO0YUF5T4MAKQs80/NPeRDW1pd+OsMmm2f6IHo8gz6yaUzfnN1cFuuOl8aufQ8V/RESI8l1DDG6iuGqzV+/IDOkFQtZTs8D2HYmxR1p/MS7j5iU5y9JaC99lBxWigI/E1DHC55TUvUEp7F332o/dDo5+1kd6FGDaHS1LMYZvqM+Qhyxc3r2YCdfQHnXKBzGrfTDS+VZYo+eHSMEUbNpkwpRSUBBr0arXqKrnBS1ebORgQXLsTOp5TeMXsFQx0Oh2ixA4xBUat4Qcsdy3MSLLJka96WChZWbjAkChAhBUZhOZAIEiUc3wvGAjLVooUr", "algid:sign:RSA:digest-PKCS1v15:SHA256": "OzqP3cKyuni28jdKlamaWq3TYDBnAZR9lfe1HGyZaH5AaVnJIFtmLz226qWRoeQlkJcqPRFaUR7YdUCR5nbeu2+LYXGTZnDQTe1F0p3a+6m8WWWV1MFcMkuWrx9Tmst5sXyNW4PfPTQrUA5+q3nNVyWA3kDddYHTOUIOk41D8qRfiP5kQcNbDPitBlIzfu45U36iY3GV9uUpSAUqPuODnq73fCR81no7lm1vvIA2XS2YfPpbxYlRxwzDc4cfnLY5o+wIqbgrVWsZrkCgqDkWtpA1UxJpHUtGpGLO8R05OVuJA1oArovPhoC36THnw26zX3I+PL8WB+z/IkH5uqCrY30UEKCiEu4vBxpCDyX4XOuoJvBEU7DI5Vj35xMsqlguBkOfLAYoTSAgkG8sBas9jy7AX4Wuv1lEf7EQGucPRNxhUhFXds23i6h1uwN+UHHjqmvvqU/KAjk6AuOL4oJL8fAhhVSSuDeJGBJqijydgeW1DVMqB8fbBIO0FxUNSg3p", "algid:sign:RSA:digest-PKCS1v15:SHA384": "m5WaMZ/Kr8C0xDHPN0MuzCaizELNA2HrbX8cQzpxoxR/9cO88DpmXiGYhmcieExyDhbWo4WdYWayTbUw0HImVe2red/tsR6mjaA+GkRxL+h4Tz4p/0uG/4CBoAq3zWaLqBy6oUf5Sgdb8V9+2GIAhKV+9mTT8+y/gr+fqKLbufxb4S6oZCUKDETFJTFTJ7zu19a+iOwqkNPW58cJWrzWaIRZohZG/TLV0G6pf0dR0tiXb7XSVS0L5trtTgPNfwVURPOajZkB630xH0KE31JHWT8R6FKFXRv6FSXrhEJiDHMIML2jRbJAy2cmrO8T+vLVLY0h4Mx1PlhNMtpKDyYIYbtoZn2NVLccGYymmeeEYdjeVxvmfIsf6bWHz959tkchsCemPCy2teFE3Fvfi0al3qHkz9g1atgBEfLBuGtu8dEQuouI0+WFs40a55F0kx5O3SEUFYXboi3vzIcT8Lm32s7tUKiBSx78TuuA+3AanWmujMFo0XjIfVjqxJRUx2xJ", "algid:sign:RSA:digest-PKCS1v15:SHA512": "g56hHzxSpmVODiCkkktaRW6poDqjo6f8MNK0hOysM9OLKxoKMEeWIFu05opnGPHb3ISgPgPtXLBJOcUObBS9GUqH+m5E2qd5Aa5ZHv/B8pa2EiGiCZf2omvuXP54nnJusDprM+utmhDQRep5G3uZ1q1/WYtSRzTtFhYhwWX8gTkr7dOM+fdtAWWCty2+kvuCt7LxlBLOvpq77RiU0A0cntFXOc3DzOSzZimX/p1KUFkEL7uDBq2JOVxwZy3WbJXVjHhZcuuNHH/AybQaJTLIrdm3/86GyKfXCCU1r1qzdcnEgzD60TOA+M3Uds9SwdIKJAxpbSb/7pa34lq3lKpd1YcmPQxuiNB38Uv5wOqxMigDf+HdWgbnR4171erpQ/YG7rSCQSB7/Jeh7lIQ2OkUe83zDbeOleX2LWIgB1gjBVMDgJqh77x0LtJGmtxwHmGK/Nr3MSE01VFAA87KlDSHQwk8Nc4wnn8rXo37hkHdbWY4sjF8kjkkMwuZ6lhqYsMf", "algid:sign:RSA:message-PKCS1v15:SHA1": "iVPY77wYQ+WiaWd8CMMxKJIhEu3nzlAGq/EFcon+hs3vIV3d1K9nASF9cUnuTFHsP6h2wN+UiigTCVKtsZtd4ZQm5QMrRznVk0w4UR+I0XtqZUpj4xXIMynwe6r7GmRBrRT8yID+aHAShV3meFlJD2pP9K9wbF07wPTlXzbyTspPduF0pkvlflT8e7Q713BL+hmPsUGOb/60JKvHt5UucnvcvHbelOUmx1ToNLpWEG0CkKIwxmzhTKJqLWL/wXR0vc7RCk/XuVl9lbsvI17lt1UHX15aj19Uc4ud0q25l55tsLjtvLyZXM8D4zonnZYkWiz0ZBdLRrKBvLkGo+ag8MXGqUMUwSMsLGKvVHLvpZCQWn6RMFlWv+SnsZ9KihzfXuiBam+COdIE7BdVM2kZK6FemjW1KWaETxdWJ/iMpUawdRIiW38udv37JdK1sMW7bC8Zqvqrkx4GhkZRtu+ZH1J0BpRsUepEn7cPeabZn2BGpElVBkukKsuIoBSdmJxq", "algid:sign:RSA:message-PKCS1v15:SHA224": "od+mpd5UTymDudy/K3hkH66NQeC8xyLR7MtE+YbdHh+LtzcelnDl8sBhE4P8UAcJaeQsBlRpG6T1XOsJtI0etSu6fTYddl09AGIBE1ITPyrMv4CYft+tRfhHGmCSw/maahmgVUk+63lcNY0P2+3UtIdlvi0cQOacFsYfcnBmPpfnIN+qb5SmPM1J0y3xPIHfTuyvR1cewWMF+VXsSxeSKz+repWCI5AIvFia/3jCPbaS+9n8s0VWG62XVeiOt+0ekPiEaqMxkdysV3N8kZ/Yg4jFjZpcqBVPcT2sctmw4LB9VjCdX+96tcKWxqPnJcBk81XYzqDerEE7KVMA72jz9Svg4o/SkCQLbZY6/utwkqiaTegOpd4blbHq98U9gUiB6h5k//3XnIEksrq9adJnuAJzK0jeGbiY0H/atSq8ulgTRuUxILYLFD6MHENc6CaAjFvP8M5MRnYFglvaBWXhpfYdYt/uqSzb9wh9Mr/e1R8g2K/l0t+MdGUlVCL7PeXh", "algid:sign:RSA:message-PKCS1v15:SHA256": "nt51Mi1IfDB2TDxso0duAQFkzwr8CrwJj5VmRAROTRwCNX3Ime2igfBeByBu8CWmzDFoOyBOWAMe7lzFVKzMFOyCbLNg/OFImem8Kyw9zN4BmB5yfchmRzcJr8CPykDQXgVdnj7cvVpdZitCP94z+xmV/AYcBfJvB2tooIWYsikQ2XsIm6zh5OBBZvV188sTzs9z/m33agmraM9H1EWG0PZZA8K0+sXUYOIEWD2uBZ5FX/6LP5c0k+RcF3jTiPs2WvhNnxmfv9DXlRSTJpZeXMxojDlboHsGqgsmT2k1geP0ecx8zqkOsbKvqQnTrsvuvesuAkF35TGAAIOx2ev3HY+mVemg6CnOZGGAEIHJNVSndJzyQrP2NlgaDG4nediZbPtwHXE2587gA+AoU2jrVLAzrinZCA3sjxdwUBUbysw5a0+XQwsgaa3hBxgJpRzdWRxD6I/o1MZ5IBfUxq7NsSIiQQ3MJzLx4HJqIBVV5fpRiNepbV0nh2AUalEzjrpZ", "algid:sign:RSA:message-PKCS1v15:SHA384": "p4NIF2DG8qRwwf5tdFO2mZVaCaRXm508P1c94V7xoTfJPnsrpkaPvkkRATnDmM5VmvzoYkhqgXeSNkVS+GR8QisJsPPswlYABeMK3mkNBxWPbjxKVVMxWcYbZnOHUMUrkHC4yAQTXFZGwf4DwTsjilGeh5iB/wKsV70D0pu8IN26FEJMp6icyiH/A7GLhtLYTceNhsLSl3UiyZzJfLrETkvg8xJSCHMw6VBH3rxiryusTI8OwMFyYDME33iYK831EYoCj75I6AqwBEyKBQTra7pa1TEHY4139YLGjhNbtSH9roLNncES8Cz1Kz1/rJiKre97skYCebJfAZ8PyjSp5At6Fxc0ITQ/9ugwVPUba6KXoNTdTHv8jjPIISXYY+jSdEgCik9cSK6Kiqino5TcPaHu6muWyw2MWKcD5lCtZKf9iDam2BuABzYgB80d9RLGBaaCe7DTCcCG/rvjs5IOc9zerw9vSHXX+tpe3S1ZHpnZgKs+CtY8koVaSKlLuBHd", "algid:sign:RSA:message-PKCS1v15:SHA512": "Pb6TidSTmUWcDiie+BRaWQg03LBHiQD2NdtZcxnC6S4MIp4tjVOWLjGzpQVbo3NiYN/EuzAEf8rCqtf3GZIeJ8eOt8t3prOipUWj6UZ0fjLFr/EOQW8Jo8oQdvmgpj61dmiGYDE4YpAHdVIffwTln28kyFSNpMKc/wFnHDJtJpj5/UvlQC6ywAKUdyq2Uj4llXUwLToAOj4VTuqPxJuPlbqmgFDg/s9niixwk/PDpxVVUPvflKnAsh2LWEQXjUcwX8stx99wBT0VnStaOlF9wDOP9LRp4OhEFOhNagZgRn19tRrV4YPqSlPoOZPT68AdF1sVieGXkWlV8ue/giRYuYeYRNCTGDsPUtC4sU8D+CTBaOPP6ch67Q9kU0/iFbYqlqWMktoBFpFfd2CxktMwZBVMl69TXMNK0F0BWmgR2YUip27ieME4ez0vbodTl7MBcvpawkruP869lbRDepN1g9ltbGKm6Fn1R4BWVQREtXgp5KSbYX/JsU+2Y6qrRdlO" ] ), "CryptoSwift RSA Keys are really cool! They support encrypting / decrypting messages, signing and verifying signed messages, and importing and exporting encrypted keys for use between sessions 🔐": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "OnZNqQXZb4KQ11TR8XY1pFMzOCBPjGEolZwQ6zpmJSTlT1XQOo4u8rf5lIYEE/qVpMyZVhIHQvHHa1wacXEde+Ni0VmIBOnfFyJdEtHQZbv1FT1KyU4SRWCyNI8g6zO4N1p0ldS1gT5pOYlrjF9VPNBpAyYS+wHbBsNlvOsWeY3r1FOtfF7Iw2V9mMQ+Q655r+sdgBYoB+nf7zRra+JwEhlOU+cGrV1WVhugHxvoIfzItIWzMWY9UCtpQ1IvFvDydjHzA3e9WAiwKIIA2dHtzErd1bAzKnkjZ2zq8ZbH+AiEwMxx7VrJBrrfCQHto2O56UmRPZubuDZHQsn5nW4vDTozo0oiSSY2x1j5ccAxcx8che0VF39OFPSUOyYiAcRJbjs+SL95XpzjMaTQBhi/3nQQIZ9tt6WYo56nyueCIv1pGoSjdqC1OuBpf2wlBitXy2y/7V4qfIYixscMlQtpIP2ijAWowHQf4swtFJzWz2nSbkc7AVlfun/S9Za8Q/CX", "algid:encrypt:RSA:PKCS1": "gob1OHvXp4NbhFCz/YjCGVk3Q9EDkjouMNHU/cIA9dggiWOUUVfFBdUrVmw+xT83kcwoLghHSQhB9G9SOvP5dzPHGa9436ydRUU8ccyfR4xsu/ML1utXMGtkx++ptOAGLjo0lvDWnKEy4PgTgro73R/dQFBbNOoALMFc8QTp0jdmsRRRsAzt1gP0coPHYuEHjce7LHrtRNjjoicdjw///wp96mJyv3jTN2Ey8i+6Ujdd+JUoS4kwzabA3Mh2SI3AvMvnWXXyTFtZFdqwJcEGLA6ImYPtMnTuWTa43tJ3A/qsDF/9Oclnj0ajvsAH1O65UbhQurzEEA/PWJHI80xjwsA5BwFtxi6JzA/A8BcIiKKetv8KhZJUF3Fqusdx+oaz8mcqOoIIn5hq7HEqIaaKiRvA2decAQeZ2jlfoaiTpbaU4i73pl8hF9ryqEpr6U4tvf6S3FaUh0PRZqhAUNeDYQJB5hn1RnJ0pF0sulI4Vu4BM27orRvUGyL9D6gtPVdG" ], signedMessage: [ "algid:sign:RSA:raw": "BtSjq0EDo+UnmKU3nC1sgzbE/0oMM5xziS+CPxuzRVNPzJj7qkB07hUoUNTEZveiqS5oY/h0Dnlu3TbOretwwQTPSSS28u1z9OL+h/D/0j08g18J1K0PymysbLMDYfhdDioDL6VoOcBEsiAQhQPMrJQ4QbQBpoz5K31irM4OCZhb3Pwm+aXBvrOT2J7obp7BLOCHngYCXvGBGut9q/CX5Ni4/ORt8vTx+yzyX7m+tloIimyKt52+YM8aRlS1DbldRgRXvXr98ypmjXzxrh6vgLIDgS+Lj3qobUeWZOxZIGQw/gJKwOMjkWyTpvn6i5Wyud16kup+xL/comDTTzr2d80puzFVMIDE6ft9OzU3hdAXD7uPr7v7Hv1BCDr4u99pcuMixuoskcNFNy4K4JPbOVRNiVGVUl6rqvyHsB4rOEDp20LKb8qmwKj+3jnP/tsJ6jyQ5oSxKcAfcLe547mo5W8AsNNk8ATdF8sw7U5PuXEdJgCnfsdrdwjQIJmI1LPe", "algid:sign:RSA:digest-PKCS1v15": "Dy8wdbDuteUxtxdYDnczmZOuLXhgmyk6pKueK/rE3St2aJU67ENYk9oXqSvX3HowbaCYxrBBnsSIqYSPo+bWmLwtDNs8/Jmlc8gHJt3vpXQ9+mSezHpK7RpvLW9E06CrA4M5U+41BeReDn2ZWZNXHOXVtjCf9earKypqhu1x7uJgtO4+S/7g+vOekJnHWo1SQ+mdx7EegtHbqP8o6zFBCR3bIchWTqMqx+oVTwoFq97VS1BZ3DGDi0aaTtiM7kTcycCY61EhFp54UZdSl2PdizYuW4l5iMcIBnbukgEFz5bOIn1OCDXKKIE8eR5zGa8tLrYWxkldamzRYWCbvtj9MxoU+rUa0oPabINVFtJKb1d/yca0mLZfZ4zNAOLI4pXcjMXbiwWCL1NiOrIPcVOWL5T6fDaSW0kaRLAKn9U2yzuzTjGu069E1+IHyt1i0M6EyY483tilrfOgd/f/TRF4azHshozpPM8kVdRZN27wBYXmtdJnAOoAMQtjJJCgqBSk", "algid:sign:RSA:digest-PKCS1v15:SHA1": "", "algid:sign:RSA:digest-PKCS1v15:SHA224": "", "algid:sign:RSA:digest-PKCS1v15:SHA256": "", "algid:sign:RSA:digest-PKCS1v15:SHA384": "", "algid:sign:RSA:digest-PKCS1v15:SHA512": "", "algid:sign:RSA:message-PKCS1v15:SHA1": "V/CYYLSo4c0EK1Swqu5L9PU4JEOAcA3XkiwHEhm4NcDj5WTgaV9XkhXzWSyo+wJQiL9m9EBJsE34V7cqtNNxzHMyjnYw6IIPOUzYy+oTFXXODjIhgC8OfqUNLrnBl0z+NQX0QJyxiU9c5cY6U3C+hDJEqfqylE3puc7EPZDsxBts4wrl3qFAzCyCgxkdla/kWQtuh0f61eVZOSN7YNceFijxe90ttHBworGItngL6dEr4OjJ5HBAuashlX5gXhEF1JAZOSGiffKdWEsN3U4RdIsVoRA+LHjJdxdme3GW+doMICcTkV5o9SB3yiiattGhVIAeFn36jvErYTD9dXMJb0CBwxlln3DmIY66lVLLDWq6ICyup/Po5NJWXVi9JvtW9pSISRR+uyqYGGw2WdegdGn1WlP82WYeO0fQT7A38dHGuVkAlArSPbIubKvwdJRcLjTobork1iBwU7WwOIcsmePsiWqdoKXsZ5oGoe1emNxq092zBnj09uMnovihGxXD", "algid:sign:RSA:message-PKCS1v15:SHA224": "fSb9Bk+9FhQ1AO5PX1IaDpJ9jjQhZa3MVOr3xC5sm1vV+nUZCpultdJBFweFKGjhQfdac5WkxMraXJD74weZv8PVuDTR0TINbc2Th+b8MGmcvJDT9r1M7l74ObTQtEAjAVygZwnio2TL/jb35OAYIOtv9Pmb8LxdwtgCvcl7Nov51bEx1v1HRIw4vp0MyxgIy1wuEQPc41O81WuUYWyv1KuIFSU1UkGJ2RQcO2b+5i9kYeFlqrFRs9iQsrM8AuDSKoqUYmwRtCdVBOVU8eKKSeL2ZIVVU2xfeCBzlwW6ptMvRUPeFu6PCMEZG/EN3BLVLbRoLOClejCUupD9Afjp7r8a2KFG3qFk8srptMZ+4UzzMoG4kp0zzoIjc4gcZ1BKCh7KCrP0IWFoWgXp0sjPjnP0D+nnpOG5+ptXrdyFzZolN6R0gfpQ40Aq8GZwt4TJYWbab2YiTGggpxuoYfIkikzUOGxR5qPjV71TLoDIyI4ojdBTCXF+SN6bb4PTvasP", "algid:sign:RSA:message-PKCS1v15:SHA256": "TC3n6BcED9Xbva5SwEM54CFzMgeTFZ+e6cdLT5GOfLpA0PY3NLiLYxIePd6GeupZdld/GYLCZipORcbBcaCQc+mnmoe76xSlMnffrvdSrSpqyS9ns/FIz0n6S9eO2VCzta03TwnX2VBcMXn3hxXi5IpinzQFKKRpRKN4m6gegzFOMSWaBNgjBlxTNg/FE8Z8MHZ0eBtUgDd1l5UqqtwSjovKhW5poI1esMLpug+FibXyX6oUm13l7aFdjyHAQCF8gCCvt3fyrY9zMFapp0qifQOEs83brhLCGu3LTUsEFczfcysCkAITjiIYb6oFgo1mWzFj5KV6RWddCIBAQ0k0f8R9Ypc9qegzr6WHhOvPhcPnDQPLOeLi8Iv/aMgQKdWy6ctddtu7pAUPQmf4WJYV5IBsACFcbuveNybL2CL1YtC7fcI3FpPRdxYkJVcC+QZ2RT4VyqvohmnJ7kvOXsvQVbaSuHl1Qmcw87MnmF2EPHC6DxGdqfqopCp6A7AJeWQ+", "algid:sign:RSA:message-PKCS1v15:SHA384": "Vs2S9PnPOFsCbiKLMSBesuMt7R3GJr4p0PUgRcOUKKv45d6KD7Dp4/GcUxgnchCBvW4SpSgRB1J4gcXhnkY06oarqwq6nQ3LfNdyns8eJJW0mrYSf1W1WZkMOo3nADhmeztqZ9/dsgWI65x/cjEaFkcc4JYbFGpqYLv7l6wEsfeOMvqOqHcIRR3vm7msgSAMMUg2Vbs3LnSeQmPKW481wYdIvRUuKzsZGKL7MEotoGM22Ix1jaLqvWrSIrsrHlqu/PatCBPKIgaQz8FOZgMbCjgxHp+7aND/1TsskPhi7RYf6m6LcAVgdr3vaIsy1qXyfyVNTpAoXBqHiUwlob145H11bCV9dlhKlPAQ35NNyAyEdIXAQc+rFaksvaVJdPj0hr+VBIaAOTkG+AHXlnuynbXFGyGtX+smHbMqS2fHhnWrLetRsxCX4ePnQvSvyN6x4wz68kaBMVfq/wwxgcZu4Pwm6rtQhTChaX/UaFKlelIS8O4NMQ1R+CUBJWMWAJpu", "algid:sign:RSA:message-PKCS1v15:SHA512": "QclLn+13g81mpsWw48n44i4mQiT4lxQaIe4R+8wyL6ftHPIZM3xkjMRL9Ij/sSlCg+pynGyf9TOBLaV7qM+gZUqA1DKLlVvwsLgSrrssKmDOE0oPEJJ9wWDNwrTWa1o42my17FMXL/+CvOA+3xw09D5bCliI1bI+SoZSHzaES/W+lgsGlMS60xMzGmiN949xhBBIFfZjvddCSuTKiXPw9ObWYz+FgQjxPnsUHZRMJCSOSYgp7bgI9q9VaoO4AOMBJCrH0rnP362B3edSNtFQ2Hm3bAnyZlVGvDUoEM9r0GQ39L03ifrDu7bdIC96C05KQNE7z/8e+Wh4pz2Ly6KY4DoSiiHC0D5+gJ2wAFb/QfQJhaZc9SbS4Trc87deyaYx1CQ/wjW96gsFXQTvoUahi1tdbBaSPqqxz8DaP9/crj2ekdR3hzxSMy0aa1/QR+Y/3Ip6G306toc38mJXLtGy6CaMm8FO23y2JykaDPyA6FQD9+toozdPQv3DEzT+0K3r" ] ) ] ) static let RSA_4096 = Fixture( keySize: 4096, publicDER: """ MIICCgKCAgEAyp6KFBHi8Tz29tMOICHD/fIiuDNCnx/oM39rUcWJ3vnqWSjjBUuZT4vUSap6TVogk1qJczJE4ykpy58VGM5GXaTgLOJkzVBEPOq+WV5n/9KwteUf0EX9oS4rCs5Vz4IbTfG7IrZH9UlmnMcK9Qm+ndJyLWd5kZ30zWFdLS8b7NOKF4SJxZ1UayGM/IXAkUuT3rCn//0qfctH6Kc8ORC/EaQeKe6T43tklMDi4WPQqc+FmV7XkX7IqtAVxcgoE0ii9XUSEru8PdtpUqDAbgbtyOOLPdg7o+M0J/J2nj9vsVJSJGHiRY4LToVeSTeM12L4AEm7yzpjOhHWyR4UU9VyIxYzrkNmjmC+M9f/110wst2tMwZnZlxaLBrXAt4g/UWULMDHxQ4hsQmCwrfupf87NfoTrElgohw2BvB+SvkyfPz0HBeJjDxu2xAmRtPj0jxcwwTKLQXD35ndk++z6PHghnYnwwqyGSPnS8/BdjryaHq5dbIq1GYO2n61aZ6Rv/JBKQa/5i8jhUC840/AgBIGcwdLZlbyvXRkVPXGEQsvHJZXn+uZZByRJgVazI6811Af0alIR/8hQ7CZOn63cfNQYpzU10r+Pi/4ep7QIf3h4pBNPOvd2tqO7PNBwAKXO4+XNdAlrIBXzNuObRhfb4B33ZACN6Pu17cVyomf5tYO9BECAwEAAQ== """, privateDER: """ MIIJKgIBAAKCAgEAyp6KFBHi8Tz29tMOICHD/fIiuDNCnx/oM39rUcWJ3vnqWSjjBUuZT4vUSap6TVogk1qJczJE4ykpy58VGM5GXaTgLOJkzVBEPOq+WV5n/9KwteUf0EX9oS4rCs5Vz4IbTfG7IrZH9UlmnMcK9Qm+ndJyLWd5kZ30zWFdLS8b7NOKF4SJxZ1UayGM/IXAkUuT3rCn//0qfctH6Kc8ORC/EaQeKe6T43tklMDi4WPQqc+FmV7XkX7IqtAVxcgoE0ii9XUSEru8PdtpUqDAbgbtyOOLPdg7o+M0J/J2nj9vsVJSJGHiRY4LToVeSTeM12L4AEm7yzpjOhHWyR4UU9VyIxYzrkNmjmC+M9f/110wst2tMwZnZlxaLBrXAt4g/UWULMDHxQ4hsQmCwrfupf87NfoTrElgohw2BvB+SvkyfPz0HBeJjDxu2xAmRtPj0jxcwwTKLQXD35ndk++z6PHghnYnwwqyGSPnS8/BdjryaHq5dbIq1GYO2n61aZ6Rv/JBKQa/5i8jhUC840/AgBIGcwdLZlbyvXRkVPXGEQsvHJZXn+uZZByRJgVazI6811Af0alIR/8hQ7CZOn63cfNQYpzU10r+Pi/4ep7QIf3h4pBNPOvd2tqO7PNBwAKXO4+XNdAlrIBXzNuObRhfb4B33ZACN6Pu17cVyomf5tYO9BECAwEAAQKCAgEAs8GfQlrz+Y1alHN9zqfmFz9f6gcgDcfi2v0qGuujezxA2kTZ03LUWqv09D3YLxPMXq4tzxND5jw4pjtGHjGyX5XMhEV9pGCXiWvA38xPe7hRqa3SYZYWg45QBVA09Nm6m5XfrdYFVOl/rYswf1/bymxPe1SXl8aIzkSYw2NN5PdvRZoCGF2R7VFgoQ+QXdatIx2ajhLuRZe4/gCP/xiKSn5NfGn6rhBklUvifI9vKZfAMObhXGUcZd4h0svWMfV5DUaFeDUxtbcYY4PV9EcVYentODrD/outU9tZvN8OmkQsN7bXZVm1Uj4j/dTYkKVu2+KORqhQK85zvQ2AfzeX/1A6FYa724J8vRzSY51iTKtoyF0N0X3lFkfF2lHWo8uNYsG/Jj0fNFnGWhg+nuOkf4a1DeBMQABmLi5n861wSDCya8zwZbTnXlR7F02hNbqh11eryGgA12PPt1bgfIqDR10nEDd4pRpzTx2+QXiAFntkOMPHQnGluzY8EMBzldv1hpqYTU3NvDq/Jfe/lGrmBp2i/C+SqLvjjOs9G9y/o7CpKMr8XMs8atHNBM9yMJgHDGVcBMNkdGFavtj0e4TqZmHcPO1qX+l5j1xWYo1nUIHFU46qWva0UjO1ZcZCV7o85Db0+vMdADtVm/cPXTiEnYAuw5mS8e4GAbNZnMFuWrkCggEBAO7sq1g35KDJXpfM+hPVRhbj2Sa3nYPEA6sTIy4fxCrlzWrOJ5+8Kq2AyS6jd7BlQFPSaCV4Uzd/yM9ANeF4v2a0vAOgQv51GAPuplhOduguE+egrWlicU5+qEw99XeDi3Gl9lCqVmDs99VzB+1GaT/ULnn6JTIQzRkCGTB4CV/tgD0hVHoS5UtyQRpnpVx3ICGVkl/JgKAsTHUJuLK8bbnLTi64xzDXScWPkaq/f9xNIXmj9HjEJHeszwnfIfmP4USm7KGHrklwx9mWlItnfo1Z7PBTOXGlItNHh4pkDbXbYlzqDQXba7yAfL7JFDiZH0sl/NtO9dOQ7qFBOCZHqWcCggEBANkZopF+4Ei2fzWCp2UI68c/Mb7UoGa2mTztZxBdajtxc3GeGlEuPjCQgnnoCaN0oVXRcdZsNBpE81r05SfFMufA4iMFg+/1U7j8Oy8QyyzEuuPErY2HM9rQ6xBCjYj24k5VunOqlyq/CfngrQ+FV8/quntIfrIMxbCgE9VihSC0kTIZU1wy4VB7DgjDoG3HrPwEhzowV7zfcyhyRdO5yi9vfaKc3EFpgU7zIuIgjEUgT72eoNOmHbnmgpCT/j/f7aGKJcK/kSkSG5bIb2knMRTc1WcZRaw6ys2HQptV3/ntAXHWFwLUbMdtJxgVDnLcoTShLWflkRARpqbUYh0Xc8cCggEBANfsk72aZcjZs99EpA0ghcNSD4HqFzRqBVaqaPTaSJLsNAT+Ytj9WSSMa0T2/sgv+T7HvM+AOtTBa13CDe/DDFdppzEvuNv2Psnu9+5+mv+iBOMkVxQSn4vs83RT2m80NuVys3SbPI1EG4aP+u344E2LGKWr58mjXXfoaZNgKDjFj0uvv4TDZu4UR7nxSYSTNDqlzi87ED+xSTfMnVsK568tiW64F2yQZF9jLKY/gvI50rL39Yze1oZBaqrlOPMtkMxWfyxMTrqYbkS6zWxfEAP27ScUT6nhL+P5lQkA+1MK/Y4zB6nvbyJgjFxvpRKxb5KetjIM3iVhqgeZxYDy6qkCggEAEINzqy+EbeN7z50tkHDaRmCXLxXLUaTICSthsIv6faUGi/jjtZMX5efIFO/Cc+12LCnvR8kZOXpPLHb+S0Ujtx8j1FgiDgmSIbsF4XGckr4wHQ0jymUjW5ySlL0LOQTWd/DrasrqDrVTU+90Gn8hC86l+qSsBm0USHgUqiGBUNiLRs1IWvX/z3hcu+vtcwxCKzVI9/MfaV1xy/zNNOqn523Kl6jo1Azrag7yc1LYeJWZmynKv+6dyjsvaUHokAE/eQ8iCis6Jm6bLJ/4YX46rISTsvDoLM6YCIQmW9xvWfpeJsOLIor37z9tPtazL6d6l58+7e03WIqPK5dyExZqlwKCAQEAoQpI5xrM76TOvkqt8y908xOm0V5Qy0L6rDcNw7+dAgzDuUb0xCPkHcjl/0XOWaE60vOFVb51/6dwrwF2LFwnv5CexzMPkzMU0odqXv4o7JtnhZ6hBa5rLjgbJQtlqxoXQNCzTo2avvZ2RZLrIRh58fZQsSiAn79RJhvYoJsR/+ulWgIxMBLgil7+kY9oGNMCGjZbCIICtUpe6kmw8x9zzc7CwaSI2J6rE8i+vt5M3gXTI6zW3I+iYGfZO/HiT/F3aAxltLd3PZiYtcUrFsxlBzLsdeJtJKqzEkCa2uyYQuEwCKrv6m1cWTxSiNrv5Lmz7cKS3e8tm38J5R6vOtQ7bQ== """, messages: [ "": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "algid:encrypt:RSA:PKCS1": "" ], signedMessage: [ "algid:sign:RSA:raw": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "algid:sign:RSA:digest-PKCS1v15": "io1hfWK5emPka90cbjukVgqd9BtIQzfCOX6+bCyQz/xQY4soEhq8ScbpLqY2SdLMHXGSyShpP8Itbb5fDjboCG9o6vMiipwndJtcR7s7owonFu2U8JJGjpcHIc1icOc+kJ+mWW0OjJj8wzx0mWv1ZJ8hHQ6AcNmzBlRjJdvvWRwZ0vJRh7sUEoOH8xXL0jmEi7JdbNcE9OvEN9ZueCVbkwN8WzezQAzzlWOYRG2zTB3JbjEUAODDK6QWMEYFm7L955dDA34vuzpLm6swZTLOlwHSvHG99G/m6twOou7kT4qxm/N1p5uyN+1AQovVGTCZc7d46q4dU09N6JkRZ2oZRIkHhKXa9f72sKyKQT4DF+Kuzg/bkfVf8Q6q3a8qFAEBcQ9rqCb/1Hgw+M/B/XfFgPC74a0lgz9BdUNkZcQZyxCJrrUUAnbC+0+RlBXdwZw436hng3utiZgh3Y25QN9buidxfkOSGagPPwfDm+Q4PUi1vC4LnDuSY/RRZc4kqMXWDRKOyfxY5bZcup2ay3I6b/3KSI0RBXCWWk+du8w49WkAf8FTqazHilAcf/GM1lWanRr0rxEx3BoWRnX63dZJkQnIWrO0IvVPGHM6Kb73jM0pImgTPIg33J23/zO0jEx19vMjcE3AB0xLM2o9Yz+Yp9EguWjLoPp8IDe9jGSBYqo=", "algid:sign:RSA:digest-PKCS1v15:SHA1": "kRgxpE3HYDZpGvahoh/pGgmCFyQ86nl5Fc+tsBmDv/iouaCQh8t+PyDVoxgIFtWvSuWLWBKqWNoxR8HHMFBwcC1RbztJ7/YQZLS2yxb/Y33YwOfSXcuk7Ep2Qhk02qvOxBkXbNGaNT//UR0Kq6vAsD5e75NhEGUjGlLugUrnqEdj2aRZkcjSE0m84CSz1lin1rEHW60Wn5qDfoIDIAxEE3Tu74HLjcHyd7bjiHPWAscqyoGgVXi/KXTvew0ooyscMX2+WG5w1lXgKeNtAGa/bb7CkT31VI9DPwDpvsopfQDXhLSIMC5W1oQmgzZbPnUWi4guYF/z9A44LNXqpZQzhcupU+6MA7k8cq5sCy8i8C4017mruFqMZ/Jo7qRjb37t5zN3aylVzogoDpXfn3GE1ExEK7fOy0kRaNL1iVTPqJSWl+kJLFrRE3NvRGTlogfSBPL4uyREYv0P+jrpyEFSGRaycA4vSvXo3nWmCWWFpboE/6+Y1PE/0y2ha0L6+kH29cRJA7lDO+LNaCBq962ZlbAjlpr5W4pMMIBGB5O4tQ8nUOK3vAiIaf5OGRkPo/t55gKyjpgf+ZMUK7HbQx09rTENf33nGsF0F/HE5vz5kQ0ifUA+Ublu9l5Pu/WHvhf3lduotMr6D2MNByuoisf5cPu0FtgaH8CseTQCJHqT+YI=", "algid:sign:RSA:digest-PKCS1v15:SHA224": "DB+dCwjY+P7gbYbs1AtU5T7y86oo85UUk1Gz6In0WIPIAr3Ua7IvtWXh/SfhXPynK4YMeg6mcl1ecGfrCJnTHiAYK3qhg4tTQqs/BbNueXLyHFgm6C8pXOrIFu5dodkEYa0lNPMSe6Au41vsq2cXfJ22Mp7MkND5gMDAdJZVx09LF3T7bbEtGyOudAToJuJoCk0qXlfVRSWQRs7HStJwtjROThWYsetG91kQZpnDptk/LMxkC1owyI2QjttAzKZ0jVPpTdhL5SdZzOMnBKP/bouC2MB0D1/xf1j5RYNjR/s3iHtiNR+CpGvho09+CrXIeo08jfKgNld7b70PHoBdc2wU/2TXTZbo1qSa3R3Ra9NKzfAjkfX+BK6JrJlhP4B2ujSuwSFHD89XFPmmL8hjy8qY9P512pkqW00RqL+w0FN2WyivIw2bazw7P1GEprSewTyWtycUrid3A3heXKw3lsyX9UyWaYk5ZTpe8Zl4Zr5LZviD8419hjdZU+Am9I5iIKhmN5+IxwH/bB/d2HlpWiG1NVtmxE1juxcgVsAH4gqoB+TgGt88wOyzzZnzkqF6XAsPszcKvlAotRaYYQNZr6RZ8uIkJu8JNpkGSh0iUm6A38Sm/Mr8NEr25aS5/P3keu8I56Sus4m75avWVvS1LEB2feoQeOSHc0mvE9QWKxo=", "algid:sign:RSA:digest-PKCS1v15:SHA256": "bc8za0TQIN3p9wCaHgQp0L3XtwB43fgxdYyYWt7XLWKJE3uYwP5RFEN3MHC7WLUfbN2q03n3dxz3RCtHYyQeQwRJNv8VOIZfnof7wkn/CCP06Fbc/F6BBdgVSEF5ZuvfLSSt3kdQM+pdjKI0nK56OTiXDJfEvpV94+AGIlD09DWDmCPGmEW/rF4gfJUI7TlQdgUue4OcYssUOZSMXH41Hy1dzUKq4aqHD1ZfGSWXcMNmslyzpiucoq4ot9WfcEZat8KNUPbwTeHX4stcEpinmo8sxOJi/wm3uY2DDOPXrJJtgG/hgOU8NvX0hawbSmgEuuOvDLKNW5x08UPWFXpDEKgMls3Oesq2Jxvm8GvJsJVchv4F50vKc0E4Q/4c+Vmi59bLIZ1PmD4J2/wkDJDfq4UrUZjPigMvGJIFiUWT0CCcdBCXZbT4HAhq/SBgd1XtYtjVbeppkf2IuC+4es0w8Cj2/XIV9QSz9iEsaQQwUh75c+vFP4ZScBGwIoEbKfhas3BivixmmUuZawYx8BsSUlEzhGNCf6xDGzsNZpKAIoVvyXq/WZ3YzIoOskQcyPhZ+39A6oEilbQ7AoDh9JnCp1B0H90jCsblfmG9Aex0uz0BEc6wxL3dp5+SOOEtZ4La6U5qd+nvcwb/Nm0jZXWxIXTfO9pxrI+0i6EBjUxwif0=", "algid:sign:RSA:digest-PKCS1v15:SHA384": "qTNv7KL5swdsK+1SJnwBOrkz47yEQFBZ4ksTfbEczDkmi6gz4Cdkq86+dbkVaypPjqbqQ9YxarEkgiSYNypzDWE0oJwp9VjrwvIOgDY+QsUlMJbMKF5XBx83f8GzfthidsDnZ3wpff7dMJyzLII5MrcsqH543Avv2WB7VDVhc62T/QkVtlfiqexVEl5SZH1g98oQNfooUGAQH88RBuf564TJnZWDklyIeuryKMW0RrtWIajN4hNh7HH5jxEBM8TFhcbkY4iQ9GeasvWWnnUgNPV8OKFowZryDHhVRFStlFkhnJAXIlEpteo4VGb/CxWHo516+hnWbixicnIv1qd4vwdPTSBBDDHK5w0OhTYaNP0jHjgs2Tkr6dRxv+F481pvxYT3hcj69Fh5bFa4DO8XxtFvbhNhP6/AMfWcZ4fxYn4XiToFmvMYa7Q3JP5A4UTeOEBeEL3LWgP//wAn4qmlj2dH5jUYZjSk+CNZeMuyXrxKklbaKP3Bjd6RYeAm0Rgp1in1MgUMd1ScQ1ic3SPjv1tdTfj2MVmJDvXCJKJ2t2oQerCo8nY/rhN95Y67OihL8LkAq4Jz2DRDgCm+TTo3x9g1WcBsO6D/m9dBihLLnfdkZFWhc1UBLda4mkqEs828B7q1QlFe7Z4EJV3KVgEkS4Zd19hmvnFeZ1H6+G2mkfc=", "algid:sign:RSA:digest-PKCS1v15:SHA512": "Vrv+Iy0EgV/MwSzu1iMODl/SQ6ORy26sCwQNuG/4Zeub5pD9STOwRuZGpXC2IM7HutAHkJDWApfpTDkd4sH9HgwWmwWdNTHz2P+UY7GhjrWsAUBz5BtisvT0dRMNIhN+NCgTtMK1wHhSqYki8FP6ZgHcS9XfMS6aqoNbKqYDVfbcKblSzXkY/002JnXFJibD+TnPSzOsY9khh71zwDSFr/93V//p16uGVS23OVBLyK8gCVQsZ7fAJNVntXByqaRAEo9QeLfQisjJUfSgvAYgvEAtcJ1i1ncsfXGLlL12OFaAFJGxtNVXDywDDKLKxMAUPl1QI0BSmS/MkBDzabiOTciZhh8mer++5OkT/OtoXSI+dROhI1F6bsCS3jWPeFMehJ8iOJESOHqKiNAE1rxxVI48q2UsggyBU+Qu0fDiV9FMz7QIw2afyIAG9XDp6/sapjSBoKyUy4t2IRl+HlTpnV4x/SdIcnNbZck4nQqGsCgF7Z0Lx5Q8Ye5fMmAVBI0iHFucAr5D9FK6/V2SHKwENDOc7nq8z29xqHdXG5NqeZqQAd+KT7Imnr0CicKc8C12Ysu3eFKs6LoSPjKJZqWUMZxTJ+lMsfxCqrgNzRbJ8n1fZAGvtQrI8fsGZ8hqvI7Jcg5fFNOa2wNr2EcbvtI6pIjyXxu/uJixdUUxq5/cGro=", "algid:sign:RSA:message-PKCS1v15:SHA1": "vjT2h52Ib4dOMBIaXsFxgfWCD14BA7XuaasMsvAeVXtpGFWbdIc7juHcSG22nzRUvSFpJyEFwzkSIoBfyVf6smJ14k2Ns+iOMAM5g/gHzAE5lpCoX+1vxQhutxFr0/VYKy9Y51u5Qp0DBnBHQn08f6zJWeULbvN7CW6PiEfCi9HFXGlPWI1jS4YbM/N7C1JqGA2kLS9JCHjdGKoMXrsvKaqurBhiQGa9mD7zs6g8EumSZcnXldVy+BRClFzidCsCZihZu3RDleEhW0jZDCmj7tvhJcleUL2FfqatI2QghgdOkJEzv3oaUqbRwI6f8klb6Lz/US8ucSl77t9xBhwOROA9W9gB732mpADUQrv9KO1BXJwJ64YKouRA4JwAGGRd4rfuvsxR6JXVvd7SdccW/tsLxQurpsmFUBrO1jIt85kImnYpSCdlzXNduLinx9psYVK+b369CP5CYnWYveMhSQRV3A5XoiyvEuW6iKYHicYnteKoN01OVscvR5iQVBpmYaZzO4QrEAAHTT40BH4Ai8pFmt/1lOYpHSzMfajIGcxw/f5pmip2KvhjJ/U7mr5uc7R46JjAFRz7DJZvvp3sQS0QhZ0TlF4TpqUVboM7jludKc6K4oUbB9vlpgPOTJKBDU3m/cwD3vluIQXJB5RyO5UtlijyHYUjSzNcScyeq8g=", "algid:sign:RSA:message-PKCS1v15:SHA224": "xhl7MsNHXUzFPNXxt/KOI6AIaFbs6QlySawLASdYScVnBDmVK//10EMAelwuN/macRLa53khIzeq6GdR2I7eYuqbBn9vKX6bdPqHwjY7Bq/fbmFKUBFbB69yDJeI8jVu3stMQ1Sv2Bkao5By1vvdVhOFtsvaRlYKGFEHBZ5UhgRDCzVtOJE5eqRxt5MjT/W3X6/8AL9jVZ7r9Q/bSo8vBJaypzgsJOfpIyAWk5qnMDZ2miexbCH75PukLDdt5hK2EsiyilYRWMvLO4vr2IA/RktLsgJmfqbPflOD72TQ2kLMxoBC4PLDXpESu4Xl3BTZrG+DRvvsHBVrYod+KadieIZnUci7pnlQiI2J63OiZJW9izZsPhUDH8Oy/ZWxAJAi+zRCh2ZyTDelC0ykjkgyaHUn+hzl8deVSKRoMpCwHB5e/XoJvVAw9A1rljdom8u01xGPgMYc0iitLO5e9wsqUhVrhCTqUXAoZyz1L0Uib/JUhS3XQAiRGh2adjEhDubwVH5vNVkqclijjSFGtMLrelGbZFcKWP4k7GJcdwlbWNgOsOUkFYHB4myERBhQzFbm9iw3wVo9tnDmqmPe1vSfDyF9wpMfsryS0RMMC284kAqXzMuHFXHzYujRMuYBNQ5dPhjKaD8KVwWYH/M124gXQXwkWWAFcXrZtHdi9wFtGRk=", "algid:sign:RSA:message-PKCS1v15:SHA256": "HWA5bFNMeO69H5+R3efkyZbzIb3CtHXW5WHnXhtZBX6sBTH04Cn5PHFfydKOjmyIYXqRQfoW8rx2bmh+qQQ3GPg/RJvScsCLwYhfL1IuXEoAAZFLVQjFCA/jddUBUM7xmPMBLonxz4ctB/T+sJfmDJ+2fMOqsuGvPodfcFflHt0p1qKpvnfg675ijbxO0zkb6ZT3jQawyTuTNhXTVRG6dhdCa35+1RHqWBFMbWdBoX7dpVM5vbQ+DjOvzht7pSHiv5rXpyy6TbtXmhHRzEuznutmCYVx1i5Wg7lqoqqGuwK1Y7DGYSRZo21cm3PKTJgNg/XUp1AL8YlJzHHkOtGZwXH+eJC0cg7TDw4KtFGRwOdFEOFxjG6ikeAy2mhXCgJBR+xVagHI6wxEGtNhu7S6eOWpeCS0uuFUrHL+f+i3twD33Cf7AXYBPFt9UizNw63RE0xQyY1pm9SpNRvYdICXSLPbR2b3W+vDykci6hNDklSO8rWYbFR+SPju3qBQbN3/m1KKqdmUa2MuD7rwAe9zcNQ8rerSMrjeODeRDx+Ol/G5U/l0hvuTJX6Gh80eK0S5qDMsBQF4sE4Oz8dQov3/Y38nAeJdz62cyS5u+r8zhE2Ici8X9ERTEMi32uGYfAkrx1HzrkLpkmXq0M+us+DI2ahLv+HE9FwuJcNCHMv3m7o=", "algid:sign:RSA:message-PKCS1v15:SHA384": "FTV4T5ZQXxhf5NkRCmD+6PrDgvCPf9e5dHbBEt3ZKD1aUjlx21U3KW6nv61lJ4DrG9woXlFfSd9HEP/viPZ48p173mR4/WTJiuVaMB6M7kRGTGhA+ZNq6RWFEj0mqCuPNtma45gUzDvklJDDO09eEQfatNMHQo2F/1oEpbfZyuI1Euxi1JnjAmMNMBJzkzsltDPdBafxy+ZGqdaQp4+9f5z4gi6AVmbu0zxGbu2Fa8KjgCUllvCQfgOBcq3o59BTtvvpYqSnR5z00rq+HPVxbiqqPxLL8ZO111oSfzSUPQ9OFnjWK1wx4eBIesxa42wyWTvXXR8QF5t2wOjCtNfhRjRfWAJOuVgBD8+PceqceRLqIMySeCmKUTlLQInrZIPp6ZBsexqFKQKCyuMCP79QA294gB8Oy6Bui5+NuWhsK+upCu2TxXhb8/Uqj8aPKWLkOwS0BVeRfwDmDebkN0XEOgVO99uxlxALj1Clkz9fBM4RbVfecGcn8y2txbAejanWTNsN9ifK6lA5NO/dFGsOkZXmFm2IxWTzL0r52HyxzUxeBIk3OnfijQpWbyRsWrqYw/uNEIYBFxu7O0VxSwvQLjl4fmj3XglKUrq2siLeQk3eXOx64RLyZ6uXeUbTn6bBcUN6iGHO9UhMPJFezvcqIWqXoCIM+/My4/7sDoYACLg=", "algid:sign:RSA:message-PKCS1v15:SHA512": "yKR6+Od3PLRVh7ubg7dIFIVWXCCQdRvKA72C7giF72cKNPzd9MhiGRQM7xEwG8XnQGwtfVTcOwLdLfXJK4ZDy8iuIxQxoAiG7/+p9X+/W/My2duUvaaiMBFStdvMPKv0guEJlasoVqI8g1GJZHen6ZNbhEZMh+VlOgDbWOPwMiYnxP+13lJ0l4AkuK449+rP4iATgVYCPBAhV9+H2EPYuNOkXtkukJem6agQAlqXvnv4WwZc8bhukVKqy7WAzYTzJfQzH/XeN3r5wVBbwwiOn0r2L1T9PDLBiTYcRxbCoN9Q3oxVwk8sBFh3mc/LlnOW7pwlME2xDHY5lfUVOq8/lNhFMomS8hkSIS53TKshxoa09vQNPR2WJJat5gVLTYGGOXYWDXFfALGmpHstsxHIxg1K4FnO1FSXz/5k9ZxL9JSgyW8Y8u+0ihkID8+Hef8Gtid1eK3kVsTp/Z541K+BB5lnSiRrnUlonVkns+5oN1Ep0gqjq0dQ1i2e4GtSX+CGzB7sXysAIxzqtHwbL4/cQVbSljFgqP/Agm4pWUpR7FwcrwVCpYLZMPTCV4C3mMvZN2EYdhRABpX2pmwoDj+TX/gnMzRO+E7yetTk9ntnakVcCNzIPt3Zhd55q8NDxrcYY79A8a65aEnYw7NTfB3HTx6wKLAgqO7B6D1d5hAK/DY=" ] ), "👋": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "fUrZJy3RZm2QJvCLDOMTiU6P99iFZ34k3GhaRSWb/83WdDerMZuN9nG/BB26YNlcU4oUkuH42mP0sBGVCppFd1W6XBUnPub5jIeT5XpHxdEnZsfx/UJlR0Y3pCUKYaUYhSrl0nJEVKnn+exqKn0ij/6lJm3y2syXsgHd4GjLnGVPaAUU08G5BnueoVaYrmh2Dwi0TRmLTMIvti3U52YhhDsSVa2jbeAbCz4dJiBUH08hqXWnTw7toBcXIhrNDmnuTGU1M/nYQg9JH/2Wn5VhGokPyLaDEGn1R2wlJJokriO52h3U63wH8GwJL2lBl4eC7btx8uEQcXjJvRQ927fNXxVMdSXacaikW+sYjzvqYcN36XVIHRDpIpZcXEU0EFNo8lmuP2LoTnCCoI8aErMc+ua08XyQHjKWBqga++XFyvJyuJEl4DeamtNUrkCVdPDYs58VYw/HzbjR67f4btRUWR3uch/Azz2mxXtUGI62uTCuKAv2TZva2ILvkGhJC2CcJNg8CYP4UqwHA0v+GIwipyoGm0anNuqf3rz9Gn1TDv9Eg6PXP11oDPvhCapvlFW4vOkO4hqQSashgNOVEEm1sjplhql2+8LRQZJuOgrp7JNnSeF/E0EaVGVy+16eF+kdBix0q4C0U9CrSGYep32zOIriMKrvw2h4tyCEalvPcWg=", "algid:encrypt:RSA:PKCS1": "bW44iL5XzS3N3CU6SySet1aDMEVLYJvQoYflPrn4eE2ABE5/eurhdHIU1yh99zriAiWlhmDagmEKOQMroxhTRz+SKi+IDUV8Y3c2DIAi/LGFgzkBdvdiLmso9bxD7kq3w+ZDq+8ft6ETHUMibYPqtzIqQ58Ob3MgDxQqLsIFtY2iHWsJNylqkmEZVcNC4f9j+3FVkYgx396MizR/2p5WDHkO+bsJvKs9Kkmn2j5jFn4344VYXJFYf2vCtl6EEavfdklbtJGlsbXTZ5v7BfPI1CA9tLpnNhDQ5KvyBoiM8+iH1yJ4bdIT+diB5z39BE9EokYC7dCDczaW+Y/KK+xfu6DY1ht0B/DgiX30O7RF86tPVB6ZOHv9arhHx/GsY/bYDjQdl31pcIQ6RNuYxu4fM8RK8ig38zYvK7p8QoqTs/xQUkfij7JUU/MqDhWr1Syk/tM9ecauryUFh2hx8bT8ON83oCDq0R8EQcM31/nNz5NdGEnYVgrj+KI6olBUkfdHZ5Lrday7XOZA9OPUs0uvnhBgoVkIyGZR7MWZNOGBiz3LFEaQPIeEoR82o6u3CNuXLBi+Zm60gxooESne2XJLLTkkX1NAQJ7MUhBIPzZDVBqjBvsTVB/McoG/2iqNP9wHdBepyGJ9cVgvXb8pVjuh32giQt6IgYMtkJkdutvyy3c=" ], signedMessage: [ "algid:sign:RSA:raw": "RVfn/YLUJklmoAOwcNWO0EUOz0JlsbOXuIaTZ0E8Bvrcxc3QRzDgOo8esS468MkIG4L4iwEPpq9mkSqbz/Cua/MFkrZrcoiKrj5RMqvNsjExVOcAfW9I+keHzzEN2ymRobM7OsbO+bovlaXPe/APu4YW+rSvpBhHRzBchVtaHdzFhrraV7tGrJZeduq5CV/Sw1eTXP/JqStqFVEssib6fSKvks13yiaWBfGEdwjkSMVQpD5f9iPeKEpATGPT9D7rolWGPMN3pocI9DVnOQjY7jPD91G2M/N6onAfR3nH/HbH01HOGkpu+DJGqaCB8hgFMhwrhvRRtw1tsBlVAU0IFJfoX9kinpcpgY5U8YYkj2SQEKB9GMVEn9bVPaoiixy14y+HQocot8O9Lb6TJM/q/uI+yJ8X2nyU9NGy1q0HNWs7xH10FF8JCHcRDZHiCihtv6cVmst6gsKFMe5c502hHsdqk5pDmjeqgwm7Rnd3cRS8VD/Rxzl5y9MJw3APBQF1dqUto/QehLswh47uB+VlaR6KkUBPwWJGzKkstAjTUDUbmGO5wgG6EMP+7MoZbOVUa0xjk0uNUVstQs8HQ7ncS8+HC6dnoUTlFjF0GY9oNOi7KJNwqwmeBHin26sBruo/rN3lPF1ENT0TpHGaReK/amFtIY3wgdg9UI74/qug9uY=", "algid:sign:RSA:digest-PKCS1v15": "eC1NYUeo3mCJcKJqcuQRl8i66Ykdy6NGQAgJNgsftcaX/BY5+W1em1LDNVFagmy7Y3Um6LjkCRbqdggAWH0iE0DS7NJLFX7EfEf+r7n0bi5DjPsjA2dktof6os86jke1/kfKkwBJVQ/FbzBjvVxrq5cCft0wwGQvTagD1wwF59+IYQFUDJv7nC17xwpk2ctPXoM2RfWlWPwmhQKxFrBPVrE6vng3Nr9SwYceS+CCeaIdWdg7it5Md6ARrUaHOqubsN5xMszH4pysPwrTX+ndY2PLqorhOB3+m8mSzXWVC2VGYv96aGuNO1ihUY0/vhvsOn1btMr/O8Uk+gLduh8WbNdtYXik7dFrXhcOtmpOWhFKg+MVwDgcvWje9tbESB/H7u+wyB/0qaxA9ZrY0cjurut1VP9GIJHG0BmooHWfQtrqBlsLFhGhklSHuomjq3KjmFEEtVWC+xfEyrnGFS+YVZvO6CqAGd5wHLlAjWru23tPv22EXjA9I5h6LjQjmRB81KpAvXsKb+3GB8YA9v0jIERWzgXJ5Ip/+a65rOpmSLwfmRLPjw9G10PjAZEBrhIAjTUZhQFu0Ito+MfVxpiwPF/k5WCuhNqntePK0fwqywvQmzsRoO3ZNbhaY9vehytB0CyqVzigXfdYHRvAwC4RJ2q+VWevPYiB6utFWzcR/a8=", "algid:sign:RSA:digest-PKCS1v15:SHA1": "gmXFm7eKWN7eIt1IvCKBwQR1rhQCZH9KHqBwHOBfVijT4pM6l7ccgucimxX0RtH/51pQblviLhFFCTMAz+Wle5aPtda2zC1U9y6mO3ytsQcJ35u//dggkO/UILESfHDkadIeQM3usxaLK5GqBgxKCg5S2ivk/m8Qi4YSOgSV44g3cAOkdnwsfiKR3CFj2gO6l3aW2tIhDHSgds4v6hqhs0qLU6xLZWUQX8RDCkVapTEZjB0df877HFiIINUMaWRpo1y+nIwaNJ+X6es1gTMsBnlogCJ69aKFhkT/ryiA0VTlyfpP/ndJXbzEvbt3U4fSBrp+jR7A6/t/OJxm5sCrGyYfeW/UmSa1xh6vUY6XCCEgrdmVyqQ8hbaC3BPKt3tDM5CFRF8SljJcLptOS/sJZMGEx+tispZ9S8KqGAqUWV2CVYT+cqHUXSH/4E8zeAuvnT9pePEZaE29P7nLYOBZul6wW2wNv+H9J8fMXlJKeM3cPYFF6X334GRvhQbomoHUm8hWMsVEvrGE6IH6HVxU6nYu3EphmLuuigBqusMa+g2LpYPGNZEE0sz8MJRi0ygAKFrMTlkGqZLGC//oOqcSIb3trTGSB30+XPEXdq0gxtY/FLmGQTpSU1McIVU5ZoCn68nzSwR9L2w2IgcDE6tfLXLj8u+4z18AwzP7buKpeFE=", "algid:sign:RSA:digest-PKCS1v15:SHA224": "GOk+2sarqkyWvSNVN4Thu2yfOmfWiHr9Mb9xPoYzgGutdqaAaD5fvHLezw0QW2QVVKO9mHZ8yShtOouioKsMWEjKXzxw+plLfWyAtvuwSapcm6ImWl5+iCi00Wt2UyBCMn+jJhzSSupFK/QZEV//pqmy9EkRBGAtXjlUOk0XqMnksUGQ5h4F6SyTIJ131Xt9cgzVN5h0/rIcoxniFQ88mq9FDiKaL9Yt9zJhengGEK60vl3Fpu5HL3PMxg48vdlOI1M4GWN96AJdc/BgE0rXlyGnEEE3Q5y6UetZ5l5dxTJKVtpQNTAUwVatLnshlBNJjYN7bldELEVdfVj3l09HIZYOVjAiCWjlPrH7JhfgVm2J1hYDEdj105yAotl4s2Fk9P8fYPfE3tZyOqKTaGxDtEINMdMPjzqcFPwKpazIoShSNFMyTu9xudonSwZk8HNi3XRhp7iX2cu1eoJ4enAkm+ORSwLwRFGR1E5CVLhTZ83gvultGEdef0fbzJyM9UGDk1sq4vlUPbNXz55sAGBoCPOOV8Wfw7h/tfzsJ6s9W2u64141s8fs5gVHqwqCGJ/L9HsSx6HSYSDFaLYu4sm0NS+6lcs/lzN3ffFV3dfTJOY1x4a2+gjPU03eKdv/YoZtzijEM04TjLPzf6eAr7/F0WmmzzdycBCEZl9eg4Cyowo=", "algid:sign:RSA:digest-PKCS1v15:SHA256": "iZPHmN7uK8r2jVkUmBdqJsgPnLbAQd9HwNErF8hnHowHS/W4tCcFmYODh20hIIok00b9Z4BGOlfs6FPqYL+cBctASqHR8FA1wD/ZitY0pfo/4UEOkM0qFuqAJ6iKIyQq0LAzlZ14o0wmpw+36fFEW7xK9zXq4AL37MjKn/OmuFSR6Tz3Tn08jkU/pfONP/YGdC/pQe55PdVxL8c1hjViZQVNoJbZDSieHrwI/wycJFvihJAFsFsdY8sa02SNqTPsBtWTlByOD3C1+WX6IZoYxKQELEw30jMQJjs2KU5eG/f0e0iwN653cm8fGw3AjPtN1CXLGDEl/gdSwHfX23972R+TZi9QkvCqXg6N3xVhXZBSj7RzI+tR1y3MFJXSqUOHgu2Vge7SSey4HVCFymExCVChWDwy7cxm3frV5rSBrWpOTJrSDI27TaB0WcC+wGGrmFavzHO5HsXeJwjUMr8wAVj5p0jnm2i+qwduThmbgMgQCPK/nG+FqGKBLA+VtFDrk4zQ3WFhCUPHhb1GKBJiJqMRGXzs/IpQGSmpFKj1J1AFZ5PSAezrCh28lVDStvt5h9JfzXmMJcT9SWQIfLmK38v53D9G8UcaWD6F0XLiEqWHaC6RhVYcpi0IGIwea6jBEKwIOpauQqE7dgT3iHM7/N/nwrjW8hQfA6bNy/d2Z/k=", "algid:sign:RSA:digest-PKCS1v15:SHA384": "MHWI/4we5lib51UOVvjIir0UGAv0wyVZnsWuE0NK643XvVGpgtxmwUwjKDZ8V2Xt1aeg8sfw/iN47nl9y0lscoH3ZFPLc33hykz4KdI9zLTyXEYptpUcdabF0SAhd35l33zo43EG1S48bVL4hPZAJVGItok/hS/DtmhXgZbZuu5kLJf/VoCEawYb6n/dgk8e9dR9GKhiFpAkgF6TZlfk7fg1due2OmcDzQ3NZZo2PQljGj7jCjBJ/CEBqS/QOgVdRquRoRVoIFyaJlVEbHHv/+E68bBhMMQvq0qbKWsvEJdJLTWWHSMhIziINWHNEXaNuoxd5SkzfRVfoZc+Zi3gC4XK2/1lMWvKYMlNgoh0IuVOJBMjIMxaW6YwtkLTkP8rAtQzCvy4VbyB5Fiz1S9rcOe9AD2TQX7dF3S0qJ2CMJWG738HK0usb9pY5q7XIzqUCvK/geOf6/UNv8Cal+hJCKU+NwktlHHGRcMmZ/HTFgiKZAWCClTfmEDhK8wFnR8N5tCUXCM8zy7EbvNYnxFMxo6Mj3Eoeo3YkXvGkjIKen4YE9NYm7VzDRGRwxKiU3OH86yJdGZE0e59sOuppMR0jUMrq/I3fmq25Bwdg7RMtwhwsh3aOc6afZw/6Q1VSZ4Q4eU2unjlYtZ6BeZJcIwiplZfYzuI9n4oj5IsfNpcRH8=", "algid:sign:RSA:digest-PKCS1v15:SHA512": "Jv8LKcl80B0/1slYYDryZDHKq2rLYVdmJfef993gM9G1EqfjZgXxtmgY/gjhSk9ZK8PfqnXbd9r+xtHBfyqCTLg4ApypQa1ir0dHzvOZsyaj/fhILG/C1pFMnVaIyFmUgU2N3sgtFJz3tbROwiwfL7sLt9EcIFSIRYLAuYVI8Mq8kTRv4VJYgtZBQXh3dc7sbtNGdeNuvT7GasBe6yzNwC5mDwhBaAb4B5POpzruyf9ICV1C3RrVJuG9Jujod7MWIh/dQir13OPgG+zFCpwLg/MFLK2pI2m3kzXsUxh4QqJ48F9LXHDy3i0R0uWYGNdl4wdIrM1cgYugksFSgmaBn394C/nL6dPtMRhAxUTUJehcw3oFeeTWWUx80G2BypgcbootMFnOEZeJO68qp/r8J8ffw2T3npuLRl6V2sbXCErBvq9tYdkR2z3DapGRVhE1q7g73OhJMveOkLwsrjR5Fr2sjB2+utO8L55RAnSLqOPKxX9mT+Mjevjwk9uGbxI8YTQ6we9pEwQUJ/l7IWakIJiVfrg3Zq9WAP8aLnku9gmhciSawNZpe6LGqdzBwwW3g6lscUceHpQ+yStLQOzpmrYDZRrjr0Z1TaRfgmHEJajLCK2/FKR1YpN0GxIkj8LU4tjT+1BDM0DqNhDXe7BNHpG5UeR5xifMJU2+r1avf44=", "algid:sign:RSA:message-PKCS1v15:SHA1": "LUGycQCpRNBvCSwTblYZMR0E9enq7mpTh9q/6OQYyP+bfry/BycWa39ChzR4JGOLPUAyCVuVSHRw0+14u8DtVICdy7rtxCjSsDBtgpfxNmRP2OTWjv+Si0W/+/rj1eKxLOi+3T1IJUx5cRxK3aC3UcmBQAOgbbcJKwmlFV6oeiPi2po6MsyqmQu5WcgY1BQtDcrmNP+1wBjHapHwxr/9cfWK7LzshqBM7ZwpF4/57aSpDa1XS03aubh38rgfO0QeYo6/0btRse2ZTjOywYSqI2Aod6YwXpp0fhfGEH4RNANDWaMUsFVlDjweWde1V3QWMFDdVHrnzguvqJ/rHRbAxUkenQgCpWcMnEP/Z8i/81gwwKAMuGo9eEkfFW1rfwOvL2z2N3AdVOknjR6tSqJmuqejRqktf6U1qZ1rUxMFRgYJpA0rHTJItsRdX6030HRROopGK5/IgGL+0/B4HPVPMUm7ulJ9et+Kk0enpt9cIDaHggL5h8DTGxKaFXFgf1A8kf50+rhD2g5vArFl6WjsJiZHhI8VL/NBgkPGKU/2a6DrxTcDZL5YhKSJu5v4QTCvviAT7sginkyZxB4XvXwAJtJr++cNkHGkFLuFGb2x549zeRitu2ZjNLYtYDBRTz1/EmL1AWGX675gauk9ajm52Oixr5ztEXfUIkVIlqEeIV8=", "algid:sign:RSA:message-PKCS1v15:SHA224": "a8saObW4HZ11Eg7sle9NPqXT20Q/LEJzaZezkokoEOVliFec3eYzPFF+rMrbLcOB9pBhye/gQ9ybbzR4O43YkxgBjt0R8k65v+gbklT82w7wLzKqS4wi782wroyO3KdHYX/InWGJ6COhptuHTJKRnl9O5rS7U+uBgIb3sf5TgT9rN192ltNlcYG4963FPf0fJSdgiO56Q3Q+WFKP1R8ix6VJLt9kT9VLdhyZSHKRocIB+bNY3JlVtczjCzFMadBPG5ZeWt+YhfvcQfWxDkqa39li4/NRJwcelN2nwIJ2kdr6rg1hQ41OtycesPnSOXWDmOdYDVCeddNpLos+0CenHFY8roQoAmA/5LSRce4G00b58kjFlqDuPt2g7BcjKghJ0LjAt0nTjBS6dprqImvSmqjMa844RqkT86O4kbfPJR1C7wEeB8EyRqv4ExeZTNU4PRDCRruBnVNTSVBqOMGwdAD9xCxuHPkasa+IKZdTShD0Zxc8iMSzBqT/9hp+P6t2IRPLv4G9ZZHw+tTGqYKjGKL2G0o2VjBhrEjnVzP4DFEWj0FOl/h2hB7z30k7d8dKEx/xvOkTCe2i0fDPzlPBeKPXj1IRAuyeIwd8aWOiRpZrd5ROJ6st/oJRc6BLizz5zstprkcQFvJlbtYlM2Dot1uLyb4JuW/G+j7torMQqKM=", "algid:sign:RSA:message-PKCS1v15:SHA256": "Qi7nNlTs5/zKpyStJWd/iHqCPjdWJmUtYG9peQXWVtnfvYtZmetLjxXwBbQLKroeVef3BN/iiScEUwH1Sb+14iXBI7pvs4BsFvj52aCzUOKmEBH1F6sms2Q+OVTABSBbBgsmD8aONN/VuCog+Mi2T9QOUh9Z9TzsPcvLeo4GtMQIeS+x8+BKhY3arcMMKlLShfEp1zysa5VOnQaX7bs0suUU2Pq3ceRGe2c5rTfgnIh7md5A5LNZAi/h/xsYQcMB6iiRWGUGIIPKwlJfL0Waskyhx6nwiVSyPyUUbrTmelTTFM8bgfPiaSFWlXXIS3dGNUzaIMdCfwXkv0M5mdoFvi+VkM2JP6GwXg9rxv+d3MTHrRxdC709MxQeLTldfkX+Z1YRIgUaDa3gQBRXOnD0l2aotm0XpjQw4HwW//P6rLg2VYbZphbu9EYornucZvtXmLwui957E1CELkEC5fk0yq8s46phEKGm9yL80sbeWOmoUvVvb1aUr8SR3iqFm/iEYvV4xCKM5A+H2YJO5V59Vdl/iv1PkdGBIcQCCeqLq/KQzcgdE3s91WCFZFGt/ngxjhyLivdFvVIjiv+VHxtYZGGWzoFWTM2H+VPzwIkYMRAa7w32FAxb5vgJGp2eq5oNPVcVp4zhPIaQYV9KV39O9ggoj8zcWdTutMtPNox0QIQ=", "algid:sign:RSA:message-PKCS1v15:SHA384": "FQivNy4acd5UVjlgtMJDtvid1DVh2+LQ9kiOY0enDyF9Aoq0omhtiAhzr2fZ2jG4SWQ+En/3PxkDjnIzWsb9dY0lNXpmq2q4ekz/RwSt4r6699z/x49p6fg3X4rCt4AIzs40dlXL728gA3urPh6PmmtzmokvLv7wNE+pQZAaNUwPkEVy1GUNY0OHo2MF5L8KU95/FW+V5tctTxyA6WHwzLZ6nKeABVZzgIPpWpOCy4KVOLliT5dnyUutXuLMk/zyKWuzHMYX0V8IBTLaqS+zDAJ3bFe9mpXCRf50xTy6Kljt2ZxmOuxkfLFMoSTC+fOg/FiHjyoM5x1VDha/Bz+xCsoBXAVYvVg/2FjiJ1GJxKV0Gdvt271Ke5fEX1lsY8jNmvUGj7VwJtmdpldiD4RDTc/f50DvpZ913OaFloX3VSiz1/PHQQdFXfGhOiS0+1cnhBZRaCHVFZPpCllLfPmSKFVWMwo4ViTJdjSr1ZxNr3xoyt1zEnVYTzirHiPPDJM63XAMfVJ1D6PKpytrimAT2uN7BvENkraZ17cYlhanp2kRNop2IHMBhT77lcrwCuAvOsMrcQDNUthMnK/WDeuUfwIpaChm1tAzDAtaYAJV1qqvqgl8CkeSOF4+UibcpeQV+JzHzwZC6FwWbFsf7o8cfvN1P3ySFT6CDjTAnqmsONU=", "algid:sign:RSA:message-PKCS1v15:SHA512": "F54RyblfVaXJQJuaiHlGtPWGAlCtUKYPTENnM4JCA3lCbH8F4nlzp6+FYX0o851ZbOA4hW0n7E65Wub41wpPaB87XAunckjMeumb7xibpAQXVvmGqG8DuOGctQ/3/O4yiTU26cn9en6x5ahPUWk5mjUgOw2FumKcBADO/bQ8pyUC0qkwzWJvGk252qJpIS/2sJdrhZQw2gJ4BpgG+ZQPDzY6BKyOD0mp5QGI7ppGkskBRpGfuZmH4ncT+Q7dqu/RkpVLEq0ypMf+ig4OBEWq3Ez1pmSd5P6ZpVLtSJ4Vg88Z/y4qe5hOv7GHLYg41LVsc7gh8ZZQwaHYdn+7O+mBLvj6kh0tDAMSYx79vN9KEvT+CuOAeLeY6phPGttwkPjQPzMDBbMVZfVcobfMgM3tEH2ICIrHZIK6ydAYva4Ulw5KJ242+hnpYktwmEeCclufkpvpq6J8QsL61RLJCrkThNNdKpijCypuBGx4C/r0sPvUUez0JcZ1P63d8ZE0NBG7aTuHroH9IaXsg/fTz43ssLbnDP5lsE8VnWzoVBA6oi4kp25/l8onX0QiKtJ/mvxS2h7W/FZjUBVkpTS7Z3HYW9p7nbaozGJmPL+dWqqAb7CkBUwkJ9Q55dLOZ0uzI9GkKzv5FHpoV+NusN2z6r/ijIGor0midOYPHYIqhYMaCKE=" ] ), "RSA Keys": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "LQy026ikurKFBYuLIuWMXy0u0gTOOd53n/tY+uuFwsbKLJoadbrLCLHgMjjANCv9hCWtq5KdyhckFT83cvdAsLxWDf/CQ92/gGtEFWVNl2k2GzEEvf6XAY0UVfk7i2qsfBgpfpebY55/npERHGuOnjsxzIMD9Qpcu8nMqls1CSGs/dtFbV+5NC1PtCKBhP11Fhr2a+SD854xBlP+wzJLb8V6gOc4n3VBA6DPPQYrfafK13x2LOmGYJ0jksB5I2N4yxJ4mWjqOhe0iezG3ZjGgXGrMrvIOjNg6Cfy4ft1onPbOqB2tcR7M8t2DbNOWA3AyFqhUV3nDuEfuUM9Gep2a6Bk484su1Mgz550rQV6XfvvWjcRWOJz7Lh3q6sJvFJmTwiKjZLggYIMZ1oD7mB0gqhJU3NxfyvNHjtdYxkDFvqy9yZTpnkEBlwOz5Q0EfqWWZTSprTDFJeQkPvv6/ZCki1ls3pMHuxAOQnrZ46vbr9eZ1hbkizfLoNW0zbuFfpA7iWD/lzfm6XIrXe+V/BSnT66A3WoYszhQ+7ru0czWZxWRJ0NdjBFt6rY7vJjra9X5lIICd5MWypTUFRh7C6AAl/fvOGui/cBm3VYc3V1iPNU1DJW0sicjtl4SVJx1em6JVv+uHH7X70mo+rWytvp9GsOM792Nr2shdYNAA7f0GY=", "algid:encrypt:RSA:PKCS1": "hsfWWoLjpeX+LnoyzPHZoonzL118Kb/T8SlRGobNtPolGRIYouJC9chvAZzT18EGd6yh/E2AAbI46lENl3YREWZhKcnKohSovpVVHsM6lVBVir7C65uK9wfKkZbiRRoc6pdL45rwUVCF2/ffGKJseYL7LOSqK/GZPZA5/n16zQ5yICnmbT5ogCxdsEQsKsBpes3rbe13/R7W0nQCaZEP0KZv53CHuNzyVmjGc8TK5bYqYOm/XwwuyBLUxvoEMfXnIu6JIyPCygiOW5nMKcfIMuq63v/RpBJ70f0qjNLMzsgr5uxxZBwXyFQO9/zAdQQpYNkrOQj9XDK+tEox02Zf5IKEgB8+27k0aHuZqDumCJDHSOzJww6jmAP421Xn/tdkqP5kcqZ1q/e7sMlsDpMLcLr++PUaZwYxCs8GO32R20krmkgu/pmo4/0xIr/HWRMDii+HSfr40fvSY9DKBgbMla4IwYGmhJXnxKQwkZ4+xdsCZ8MhPPlC5wiRYIsuPVTKqAwPxtS1obYQ1oUZgIuKSI/TPkLNLGrepbJRKVxupN11PO0GdjAWratbIkrVgaNc61N7tSYQI2ny5aE+fUz2re0luUapDwmA2PxvYIxke/5rqIZrPWw65bhjGQoFTcu4w0wr2q+uMJvoYpYH2v7Ptct9K8vGXQ4u7BKw9KQSvhY=" ], signedMessage: [ "algid:sign:RSA:raw": "xApxotkihJbaaP/UPBR/nn2nWv7t7cMqX1w3l3fn/+FblVM9pxet08Z5TuQk9uJMxBYeCR37rUDxeYaA4stZ7lKyOZdh86Joy3PMcX4H7FnvzkZEB6KbFmpif4MOJflCEt0V3NpOW/NY9rA43c1P8EDVUYmnmC4qD9gWUvuzDHccsUas4IgUje9wHPRjt15jp3YYORRj/RRib8vTzcD5rfhliS9dmAWu5f55CD/nc9M9UaIO25bjvqoMEgykg6qRAP/C2urxU5pVlptxQavCwx0762bZhOBSm+WpDmmOq218tVq3v5bk+xEgZYR6kQoS3kust2FiBPbRvqAHUvwpREJN8eY30Tbt2I8vSoa0YejkJ7I9+2nj/dJPqXWkkjqdQWLXm3zP7zqC69d8RGjjGnpbuPpKgB0oSOSDsSrazJtOWgyQsnqRgEsBZtHWdGMAEZWavcAdbJqkxAyK/JCy8J8r+k0RB4wOah1kZZZ6uZlj3JO/rEx8Cy7STqMQJOyRarwgkjo0CCL4qvREk9Tb+QsHNp/tbmSfNcB3AgoO7YHwSN7pTRf7TlXXopMthu6jlEThJOf5NeIRC5KGNDMexV4HuqL06HdRBveLBU4DDiE6Y0QVZdLEu8T5A097qHhl5zfsjW/VlvUFXsR2gy9Qo0mJrhO/HUhlDO0PNU1oER8=", "algid:sign:RSA:digest-PKCS1v15": "jDhhAD3SKdB9foLpSM/Y/+njoYIHzCs2ImlXRcHTlQZXV9dGejae/lcOzr147M3q6Kr95g5RLo7sBLOlw2MQS+toSAvPM0GrDZRJ5ZB3fEdHs0GcmYZEIfu+7h6TmU/Msbl3twloh70To/h7CykRjDxIolJx0sBCIzmn1pGDxuNJtaWf0FEnj/EvM0b9pixdN7b4fOxG6D7XTuq3ZEqWpxqC7pCZZzu9piuCKCaRUK/0nU4M6YGwPnI3Ndljkt0alIkfitmwBzjKwYo65rNfq02d8NFVZ5eRZhEUtfpTcqaV5Y0jSEM47MnL3kUYIVHjhYecLU126J7YlTdPTcOJ7gM8cMsrEUQAVCif+kfaeeOsR/cSej4yyQjQIvVP2kho1zJxlWX30sYoZipzoJcFdth5IEBRO2AS3ZCJWiEagDjClOPWSquX3XOa6QKjH/4aVVfdM5WlzdEIkNxeI8i04mpgtQnOOR2NXOy3HW8arz/+L2riVbf7GjWQ09lvg5h+mqXCIkUu7j0I9SsHahTk6bZQcxZJtblidFXOLQP5BKst7F9FGfAZmaFZXTRKNYyHf0mxpe3HNEEYGDepUJ686/FUfS/W7Qv4cEtFR/Blr2K7rwOeqZYX9Y77rSCN6XOM+KZn1oCk3XoIuGJ/tVaUs7qtHrAurRdo30e7oCI8TDM=", "algid:sign:RSA:digest-PKCS1v15:SHA1": "SbLKflUrjcK7gX0CO2KY9E7A4/P61lsnjaGis/y+0sRjfcYVTx7gsR6yHLl9j/9e+2TcXdpS573pBLWAfgzHg0p0Fz62Apl7n/v1xM6FSxrIYNXIz8ol+yfwt6VuwpBcfRSwEcdVpNqW0wQ77RPVGWZKK2q+AB+4UJi7D7fJNnRvNx1b2rOrv464k3EGBnymfhnS3wbkYCWBtFMUcKqEn6jY0raqcTaZ0+GFOA3gWYR55qTWgO/PFwHhNAv1zW5P8TtSDMuWtnCNM/e6yx9npeOliPZdqMnmpI5cWadZufLsLu4p5SmKDHda0qDceDqYlc+b8I86jIJ5Q+WKJ66rqV4vKi5G3LisLLmiZkGpX47e8nS59RtUO8wDl1EBpikqsh71EUFfReKQ30n6mDPiE0Nc5q1fQ2LiTDqfWpWFvNLY7CZd7QqIPCPscdF+B0GqtR92cInm72sKKSkDIDJQJ3+IEizna5S62Fgva+rjKt1zILd3jprcKoO+HOvNeLaBrGc5FiGJD59zCgBKWdCu1WKQapuY9ccb3b99Ss+imkOz6qDcJp5EI+XSibLijCUCJBcgur0ZkyFxc42EPtahAk5hA4eXeFzB11FLSsPFdXoeJhwIcbelre93IOblUYfac+YK2V4qWO6Z+j2J+AMXHfRAbvQ+/+GHiW7B75mTFOk=", "algid:sign:RSA:digest-PKCS1v15:SHA224": "x7s2nhZgMkvI9/dauNvKO3BAkRivzmuc20t+rvjBTRiIzk6hx6CiDbNcaMtji2ZB26okDYeREaHz9QY+/5BiFO1Ub88pWMmP3lKCtnPwgiapOJgOHA7HIWZ3L8v240prf+HgoIvZYiMsuUNmCtExgG7+O2FsmsMXPZnTbugCgU6ieVRwXySWpWE9mcPvI+Kf64toyWIkEKPNT6x+ry4ucD7Qk5fbdlX9PBHzQljymUMqMVtXn76+TTew4GP9vf/JjxHs8M+2ugHMFSMamE0cBlghBd0lnpMLpY6DELX+zto5T2ypdywAXvSMPFqSj6lors2rJUvf2/iGnGlE97Bz6s2n+yWVer5mThUWbCsvzF2xZU3akVJ/tAhMvXnEO26QDFv6ERYytNoDCizBvsx2xn8FU2npmufXwSCcM/Htxrgn5uP5yfMjVt0R8VNbl2T3J9JxmqtlO9o34x0v46tyhGJsS5iRZqv57WKAuu6oHYTt7tedjyN+FZnvrURA78Uijg63VL1SoFVde2nXxaKDAjMg8/pvbgI35cCqiREHLGpR+M0aOtxUTZD/OtfZZHRc0Km+gOjJ1YJm8A5R1VpApVK85qEiSFtROsLpSsoncMBslJ46DQJTeup4/sJB6rtAVDMMYUIKc6dr8xZaI4pZ4Gsd4aaBB5ntKCI+fqdAqPA=", "algid:sign:RSA:digest-PKCS1v15:SHA256": "OjqBix/b1jwp7jdfkdWlHE5dukr9cR2G9a/NJWWtp910Ct0lsuNq8KhFe0GywpDntDqowKaidDV4BBAS2SNTFREbKy2zS/W+po7DaTZOXK+9gsZDpNDU9C3+x/GT0qhZp6ooYLVRT3qNE4PMk+qggB0x+H22CLy+RmDX5Kue6WCit5PjEWdXO+drSahW5P80GOKKSlM46gjfW3mTx304fr+WJXesRlHEUeedTlhgl8SZl1e4eFeS+gUIkCjgDDwuPDaOhckJZxVIvfk4Xznp9mk9K99ZxwBW8T4fwYf6vATWXP0FOWLkGDmDZHT2MnnfS442/27Ipox1Zgi2XAFkMXAuFa0iLl4cw8j6boruC3FoWqJ2GEDFqQwY6J0NyGT/5tDOk0DrCpxk2wM6gq/kGwX5CbJYaTfyShhXlPVYG+OyJhedJRondns1My0oOeVdeVIpRfKnIcVEnihmsFfkryK6fh7A1O7JSrqzxmUYnvtDjuGZ3udYBXtN5rRfqo2XndbBvT+UxSZzgnlOJPgJ+uIID3Xd/kSqwrYZux3Ooe39VqVg++xm8cAIN0sdkF5FV50XGuXgnSAGF2GIHZtWcndBMMPKvC7/znW+wefjvjsL1Id3avXYEgCaDvcS1pRkhpKpSfmOKig5ttKKHKqDY7wz5R9S775jGByHLcgoiz0=", "algid:sign:RSA:digest-PKCS1v15:SHA384": "ElprLAsYrMqVRuk6vydyrzQNOczfh2/udvt6qlTl9D67PjXnIz6Dl4MqwFqIo96H65pb2TAGXK4bCa5IcrnASmLb3wcIQzpNvbU+QeK/GXs7KRbBml5MgY4bBNbLm3KKBCEVQJqLAg+HsCgrwkrEzvp4mZ2MgD0CfrlW926hxDrcBKr0HpPoNmFRuwDS7UN3ro+c0T1T2YqPfNpsU/5gyi3oFQz05RpFdpSyS42lvflQr+lPZoWdfTL0tzvzXa+A8sdLJYyMC9d33a42Pgnhce1EoaP2q+qhOcQKnFTenVShwTMUOARIEz4o/8gO5u5pJ8pnz+vjs51DKPBSvgM/9uooVCIre5VDeRjnVgsWs3O2EJynip60dOqzncPPwXpPfXibV6+ko060mLrKyn3oU7Z6RM9ZEB/Q3nyuTG3R2ZT2MvlFZ8tPQzmSt7zUJWCJ+1DjsuDoVj15HOdlJLATOUFBZ5WlRO4wzHyDKRgRHxxsLfwnpDgKFUgarTLBnpqzyEuFxJdGMgPfqzEgterN9ojQfWHp0DlxWXrn2cf+uf2SDoLgeGcPd9zh/1JS4RMS/XHpA1KTPr9OrqpyS9OXVwTTWSEhWz+v+DJuvsvJwQm8O2GxukKG6u4Y9MnVtnTASI8cgTVNrQPHrt5KWHAS93Ge/mJMPMpjTPBQzCw3ZqA=", "algid:sign:RSA:digest-PKCS1v15:SHA512": "ZfReBmsAM4vPICtGrKmUT0hhhyJUGlsrFh+ZUfKSHNSGiSHpCQMmQ2IgEnskqwFlCEwCB3Q18OHh1hjylQm5O+PgM+RdRVKGvEJTtkovueTr7ow3Vqa75PL+yPt8dgFxSVbZB+V9d+cOf436MwlJPS5qQjq2MQ43Wv7s8DTwo154z/a+NciC5sPCftbME4m4RXKpVUDDI81BGdzrwXWy8w/nMrOkoPFnu1a4t0IzaGILiMHRRFNOWxsIsdEjGdAtVF9rfqku9aSrbB6cLwflG24exBzvTuleKjN0nPeQytX8xNvsivGm06n4YqCCPIJ8ecirNyS9gzrjRl5zSp47bUt15XbFIitJSdOaLDmBRPqDDCS2vhAUIECiGYHaT0OfDs37wCmRo5mER7B0T0cakkR34ucK4/LlUXEjh/jQhT7aDJ0wxDxqXHrzDrFPtHX3EJQ8THn20/gy34z54giiwxcZ5mxEudSxv075vDwbT0Yd8RRX6B8BJK6Q4HSMIrP+RaAxRIPoMBBXBOXKBhqh51MXnBybilmYfaYn33m8sqVBSArc6XYc6Glhe9AdWS9WA5NMZeX8J20A3q8g60VUVPq/PNafjjNo1594TdSiOpmNIZhRekoC1YZe2R35MDEoD6c+bkvOmRr0d1qgtkgiD7hwKjYQkcs/ODOZJwqTac8=", "algid:sign:RSA:message-PKCS1v15:SHA1": "W+1k8WlZ2q62DuCW9rvu7O315mSeOyu5/jHrQOjwjFfkSmPTvvmBwtJvDGuK+NFbjyxF0gM0zXLaTwpGfSllDHNlizSmexl3+jb5PXjvj/Szr5Xn4HtmoeI4l3HCEDp8OQTCpbyDLF/KjUAUC/rB0ZHCbJ8LPy+53nkhAnOiz0YJIx3H/jrw1bZnSBiJvBQs/ekOEvDEJsYAFUdRSayrfcELujARk7t6OZ5E4uO2hASDfqLT3A4hhw8oiz2IcqaRqAWQx7N3CSXIHveZb0KT400r3554kGvJ8UEh5ia2OJxTt1Tw44x+1h+b6iSA4uaCUTan44HDCNzLpBwPeinkwvFaDsKyKsT6eO8XePq+SeRpK6ZB2KFoEG3XB646tI1HmbNiC7XfVCclQe3+osjWRkG20hSa7ollaUI7lDMkCQHATpIBJ4v6FYlfK5OoUQxHQqKUUMur1uoMt101fyrPfWe1cIdEF2UnBTsX1jE6W8dE2yMPLux72JsUsqprBEFdaw6gcm4zgRsJ8V22MMAQ9K9BtyapkmfwIvMYcol//GR/kBCo3I1wfLc7JeBDSr1aYFyq4w0cvW+eEdGRsCeUbrgAXZ4DIaBMyf5wmHT5G07ehk2P2iP7/I7bvydHxgvmm7tglfqWYjCxxnqYjuxNzY5nl3jwHihFY/Lfx8nMgRc=", "algid:sign:RSA:message-PKCS1v15:SHA224": "UQkToUyUbNQELROez0WEf3cWJti+7sAhEWE488y6JQ2w2F9CImcWVTyezAzt+mUs+VpFEEDBswqO0Wvgsr4FnpHbAIqLGoTjajbYmRRqDey5vqTbG7bVgJeoNI7a8nyXoLfSH2be58fK8JB+HPPdMFHh/8ZK0rRwW73y1zoyXqNQpbWrEaTSwg88+AJ8PScc3jqVd6192LAM9c8IrFrfSsmWHJ7PcGHoxs5Q1UpBsFZLoBkcvTPacAU0jb1V3yG9eyDaU8Zy9T/cMrz0WsM27herQb9wAecJG3rVK4RZ6bwOd1uiSt2xcTg3v4FbYhEGNH8LDvPi1HEJKGFSnbz4Nd79I+WLXqE24gOUKqwpKBw1NPLPxKN125la6al1ToSZGBBZiyRbtGuMwBOgnPBlAsU+LnvLRCRilaAlN6TuNl8lixv/no1j4jf32FD5f+xfj7wlxLqaWkqQKx0UXkhEiTZ7lw5LaZwCQa06w9jV4F4Jewcn42TrLjQpik64eAyBNQHMBhEnGTMYCqWUYaPV+rYxEiViezqvJCeo307AFnHXgXXbnkQriaGANLpyMGP7GyvOk+VtfMEXQZ5OChb+0cp4Wn4u+scpvhmKvD2t7gZiiQhNBELeiMENc5E6LwpR13eoJjDQ4MHWjPQc/bAZfqH6WHAXyPMyVCjTYVKE+aA=", "algid:sign:RSA:message-PKCS1v15:SHA256": "eFmNictbH/gHOJ9z0CS1Iq2McAr+jli7DiCFA7w957H9DejodrntVkm2nua7NMKhR7abuwP+q4SQFSoDEp6rZsxn8VOhp0vidlojR52XNiTE8N+zV89Ir/H4bT7SxAKWt4njc71/DVlSug8PWdYw/CfD5uYPgTrhVkRsA0y060NuPb9V+b2LZrMCQFLm9F7qLOeJEdMM5gLErQFQzOJro28vwknqfyC/uywhj7yaJ0+2MlTxrxn2u/kXuqoDEAKLVOMRbYLiYgidsqdBJFs96kkSALWeWShSZsX4qfH8F3lE+PmiZyJ2wRfDRfX6TKpoPnFaaXx71GoO9zq9crxcb/mxqL5PeCgUCJiIolSFiOom4zx5ngw0qbzXx7UrSjEcJ/6OWdYfmhP2EirMRFOfY9G5cahJE2MeoFid4dA+nLJ2gvRYl88NIcB5ozmDRd1XCglfT4EBxC0UGbyQBzuFwAqgAOLAXvpm7HMuJUMHP/XYGg1RVC+886h6OBI6KTqijUql9PO9fChRui9JQM6gZl1/7y/UvT1ce2fpI7HxTw3zvJRHP30TKmGn12q4by9rCzWg5XE4/HJWD2ENy4KShlVEJF0n0iNpLInAiE3hcVHhcLaf4XZvqeSX6JjwEJD2umJsb3ev5OHJNdRy5A8x1DLv4uFNALITZ7XzEIlo+1M=", "algid:sign:RSA:message-PKCS1v15:SHA384": "EQi5aKYBmblsgS9IJ2SpcR5IQAE8pwd+E7gmL72bYGgarEADPRB1BZzrWjkTx2+g1HtXftedWBU3RcRaXdhv3iWa9mUXWMVjG6VNLvzBgUsyVMXTDIq9Q9xbTBR/jzxndTzfrTvvH7v52iNRpujoqzGibrZnVFDT6YB3xbx4h4pqKMA4kilmCz9WeQNTHUfXBoVYVvZ1RqzcoN2iJoU2f/bOjqxa/ZHNt5ZuIpIHrAkWkwCRv8y9nWf+BIEb/pSTUN5uapwo4fp2BzR1Db4SFhMEEocdkQvrgX2PUGHeZtwY9dOXAR9Y7qbjegahvXsI1kkHtCozI2O6yAUHVOZMmid6vXaTFT5E6C8OYfbHp9dqkLG+TGnRVpmAEo6FRP0MHbE5BocQkUMQlxYqzbrVBf8WMtNfghyWzqPQvv8sIVqoeZ/cuE8ywqwdWULK2Ldm+6tPXOtdvG330Sp7YgP5B2dQxzPoFXsWs9kkFfnwoSgOfR62GJ/+xrkoeWYXcvBlg/jTp/XsAD2o0nUtY+jzh27/ojZk+hm9qfSWKJgnBndULZym/Z5XKYZsui5icVUy9pUvJtPlcaJlht0xyGr7P8w6ubh82a+4iQ+vhq0Ayozg6ubCGvNpgY+Nm8pGzs+1EiIxmnmCTyq6rY1mlmWoZYRJBlZ4DowaCHzRNlBV97Y=", "algid:sign:RSA:message-PKCS1v15:SHA512": "RipJ0BWBSJ1nt4n9iGz9GZlBv2rjeZPJoxxqcVKVG+Jlee2Nx6ETP+sxdM92GN7bMGT15qMvY3L/3oNWGiP+7Oju4BmFCXHePozkAb94WFS5yvlVuci9ZsY8NAHFaEHi8kQoWohku7uZ4SJ5aCrVpYXOaZw8/5hpoRRAS058YE2chAf9h1xhtpL96wQlTawKxJIyPu7MnDDI7NkvOx2EnJl3E+kt4eGCwvt+He/E0GsYPrUIFsB4+onU7279CxcCsw0/tuP2WtLYFxGWGesjY8RklfrP0xjrRudMSP8s1zYhuzUhPIwefg+xpCkW6rJoTCFxiV40Myt9/PZIKovO7r5iFsa/jT/9o+QBd2v/4gKBT63h4mKPXriQEjn1zha3PlCT5tf1Kf+JnNZLufLcZ3zkenlbw4fQ53HTml2VCae4qruVV4IGo4B8oixucNkWeQN1167vFx8J0BfPAOeL57UFo1IdzM7TQmSm95aqvBke9tF4d6xWTAxMS1EYyyLa5FfL8FfSI1IJnFETyDwhP3IOaeMOw2sUt+iwMQiZwR+hAhQEi8FE1zhAQ6NOljoMEWT41YUbchQaBreC+quelIWraJJjWZ8QJbnMvmAodE/WqMRk1qg1iC6cTBJdzdrb4jSO/eOui1rhO9wyM6KIfeTBDaxbqPtWDWmvobSLwGY=" ] ), "CryptoSwift RSA Keys!": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "JYqLmIFJR3fHQdqy9CQAsTkY6tE67vxkpkqnte9YY0vjVWGfDzX2s249PgRi6HhQIUhXI+++Awdo0bDewe5pcGXrCV/3322wu0vDlJFDpnvFC8mAH9m94pIh6CZ4jpGfdyz4+fbQOCZ5vLMWo36nRdXbZz4+dyBPvhlTzIO2cvpcA5ygBszIXhK4Z7LXyRNpcWxDCJKKD7xoLXHFa058y72XU23Qpyh3syXoc6lR7WOz4hWYwKJ4RtXg4yHcYNFuPCbR7glQNjPAMD9Apf/UvTFMGAgmFUhNt/qnRU/97uKGFMISJRvCVDxuynTDImnYWONx2u89RVlD0Yd3Tf2nIpfX5cLm2zmoLy7tJ8ZQOzi3nYcd6LOArwxDekQNkTVw9y9nYMas4EIGUOOr3OTC3RNK9Kt7a97L7OzY8R5+4rlXLjg0OuefkaAN4MlE+haTOtWICi3G0DuNnypqovCABnIVqRt5LgQZ6uY5ZtZbZDSyeIjQAiejlza3l0LReU+4sa77tvG4GkyCejULKAKVZczRH89q30dNVX8kqoxUNDnYICyfXwXss7XKLfF8AUCp1yx4yWzJHbw4Vq8kkw7M2ISgFQwF9vI89sjCZlqxtDfjSHNHz0vezOehtP1fs/P5re3E+q8YanhnJAg2VxXU0Xv5BdRk2j/CXy3dOtEMrLo=", "algid:encrypt:RSA:PKCS1": "uUT3t8NLWaZE/qCf9UaYUpCyQMkovESE8JfWnItU0uE6CD4NBTJK7d8kSdxBOeJL+vJBIqDkm3y7aCMEB6ah+QPRbh2NQFvPS/oilKE9YAcfZBa2V34bDCN+nr7N+p1UzVGPOdQeyXwh31/BbUZcZvNvQgNTspk9ZJ+5dEEnr6ACEipJIyjsH/pliP2kmfnC7KS92l33x0uT2sXsiFli8khqDCF5LObN3sGV3iCWwFyUU2nacW99HZ1SKkHryI/tfTGp+ficcUdjFxyb/Cj9RMJ113f7Cn3eCejXU2MLErXoB1GYSyWK9KccstUD4ohtCie225vQRxj0r60FlX8iiHD6ieEelPjT0cRqGNX7rmO5Tact0ldxhAQgoNOkmelMmOsjkJFwX/PaM20BLG/yr9WH8Rpp5eDlneKOE2zfQEwNQA8mYD3JAH/Xk1lx0ohZa1D8ZbJvbr75IPk/Cmf1DsbyvVeA646nKMMIzoloPU0Ux2PFVD0nu6O5Nkehnob8bkyPQ2kLNpxe2x08Nq8XsamZlHd+aMp91vzdbIb44ESzRX/JwCE/sw9NN6/focF6aVuVO+3syFUXLztvyre4QEw+lpmPDt2KCIGV23Gxw78g+nvBdLDjKlAnvtcjrELasD6VHuN/pJVzhx2n+DfHBbhjYt0KtNuRDdKMjSnjFJI=" ], signedMessage: [ "algid:sign:RSA:raw": "EuJuercZFslsiYtV9ynodBp3ov4AiE8W2dzMUJf62HeDyGANOEfRskUGzN0Iz7R/RwxfoiYEAKm7jzU7zWZUu/3toRfYkJzLE1V2+q8XM3DLUejWtfg4fTypBjg0gb8lZkxv9O1EZfwAEc/QHrDbHO+UL4ZPOkGPpBi6nI9m/ri6akumahYtt9uYPo6xQRmEd+1asIFmu6AgFR17L/wjRmY21UOMs3sUcSeA9klFXVBZszl+zF/abiROkrhA14wf9Q08Snj2BQwzrjjzpW1qlD1iDkd4gUJwL6kTc2r6NK1BLWF4PJ3yfH50Cf7cf9eHfPTFcROwuxFEVZmqJHDngJ6rGTr2wOXuT/WJfnzUc4GId1nD/h5rAZCeYXmOiksn22MQkiD5GHrsg5Gf1aqAt/U8X2w2N734X6Cg4klv5vB2CaCcCSHUeKb8UCx448aRYdzCPV0rm1z/VILydbAKk+l+Yss5fGHQtBIaWU5I7Uu1d8K4pLiEP0JH6EaQtr0w/E2IPNWjRcroTvfu2VyvRfMs+HxSARJ/OqsNUvocp8BXjXV5nYnzaAqmPQMRg0GRBo2k6G0zYpRSowwxvYjb5g53RZojc/zDfM74/GXLyuthxGCN0sNwAWfUtaTNWgglZTlM7zJbIlhXrxXPNjO34Nl/YbH6x1IzaAxXO3D5Fuo=", "algid:sign:RSA:digest-PKCS1v15": "vu0PRjG00nkdyJQKAZsQ5wcnvWOJwcwAOyhVj1LIyGkuv6yp7mU4uMLBEuQzuA2Xsorewy18BVut7yPOGnM97yMgmpAV4SCpk/C/0CVfXIpw311rjiPY5oieh+TjDqiqa1TTxWTjumoMrXq6xP4TkZ82DqIELXI7K/I/fic1GoO84B+EJR3Zy7SB7EIiyTMRCfR5JLh9lY/BodmvK92l1WxDTQG1u/cBanw19y+V8fjrHgu3VckkhhTMMT91LC4knUnzgO5xi1LTUoI7P9Zl1nvjb3o9cV11xKpK1bf095e8ZKoWBcZOA719qgfQbRGBIvxJT6fZYEE1XnnsmGCAEnTprsqUKBDYgHz5ZpbaYpMisu2rN/VrxY+I/Pe5bUTeQnPWyxdvMwvVFTaIofDkv5alzT+ykERFfwd+1ic/Ljz4M9YN73Rh5MNeaSw+nTJ+l3Xsi2X5ebq9af8/1tFSaq/XUiaKULcYnJQqjYEh2syQbfBx+puxIQwYqmT8v4f+Aus/7PMl98naeX7vvg0BjqC+roJPnR4MHc463PDQMpZBxNRt2hHPoASyYAJ/5wg9VLmuZHMA0GuSUiyludBlac0hPTvhq0WXdCuSBklRECU45TjM+X95F2OyRpo5/Xzh6tmhnA1+fBOv9oOBgUZwR1rFUoqg0opQdprGMOfrd1I=", "algid:sign:RSA:digest-PKCS1v15:SHA1": "", "algid:sign:RSA:digest-PKCS1v15:SHA224": "WvGFjDp+NjT7f/3zGVkhzlZg67ggmCdClokkNm4l7SjSyJUnxACUX06dn8DdbUjfAYYdp1sgU9F35GkuaviXipnF4p+nPvaSYNSQIApZ9qvYANiPjd4BJjD4/upaK8iBJZLm3s7jo5C0MSjRRIkFkD9gbDqDqz6B0DqJpnHCZ8A4gVxuwS7Taw6+3xwolHp5u1Sl8uxfiyYBqsYNbD5FVAborL0bK31l7jnoUUy0xAhA/7Pi0IVWVxkhZSIccyKwGQ27sSwslLwP7GffRiHX1dgL5m2+fJ/KtCAVuN61PWoJTWU0pUoyFqtRPWLtxmIBqp3/nLwU5h7LSJfKH1gdJBQ/EHr0yTNj1hUsghvVGNSvWHmCIQuSnQj+2m/mgC1CRx/TF2Y1zsWof0cMkLdKIqvW1druJmLJjOA3afyXcbHjrNQbSzV2kZGp5yclRQi/2GrnkcYWuhpEmvppCmO0XyJJ7zEkNLaLxVPThcXfv4IGdHJVV8ZQ0K3ytNkKvdIesO50/mkcQ1KlrjlRbehM4ehAJAzQxqlyfAFRTTRyPjP4Y3ds+jiYR7OW3tVZJf92sJcpp+By2txBtLjZFAW5EDLQAF4uysRU56tYP1qZZ6hE9iAEOw8nxHuQziGJtNeeP6pLk8l8MGmshezNNhCXbxfhyON8yk7mxPqiY6NEpr4=", "algid:sign:RSA:digest-PKCS1v15:SHA256": "x5wYrUzX+d+I+Wtg52NUrnX2Ih8Mz5q+Wl5NPFCQTGVQYOzhN4Y5YLAtdXEPkmd7u/17O2pi8LpvZuuaXkypC3brZq9GLokKDrNEIiorJdN4FuKs/SGqnqUM6B2TYp7QHak1av3FndEQOnQz/VcqrTEWzq0iYfmqqJM4F52TLRp/4MUKE6F4mngUNfyqpt9ts88rGBQoNzzYDMpgolimfUtDh1iUmKm3cSmuYvuYtASgJxGHsjxN+H6JsGHt7ltYeXh2JL7qeDGQ5UB5YGYyWJiTBTt7hLDPHULuOXT33meU2KuXYZBul5+mjLlxflNdfgLzceYvZc+xUphYl67dqyhnFTsD/NCmuHWDwKmcwxXrrzA6B/BMCxwkmjDJ6iOdtnCn9RmPeB742tAFHmqfqRBNQAXhgDfH73cNauIfbKsOEdjP26f5A6Zuvvr91YniZmgaCe5qwjWOC4PBZ0faPbtC9z76qTrn742OgZ6b5V8vUMlivOWsv6NeVdKRb51TNVsd6we2+MKIjmBfWoV1L9Wapuq6ln3Ipei6ujqJug0Q3Lo0WKaXNBJBfrtncYNR8A81fJ9Cl2yYC2vO7vmREqvqQWopx91Z77cs0Rl5mwRpfMzn6ZDGZ3MmmgNfN+1gTXgeR1wI/yoy9h0plpjNdUqGhuLvSZfaChya5XeMyRg=", "algid:sign:RSA:digest-PKCS1v15:SHA384": "hPCBYxTh+6YInYogLRih2l1ngMC2HFpzJ50et/i6MX+4GpqezEnpW6EqS6qBuqG9GVv+047OeO6a6m96oDUKG7DBU6sndZOoYVDuGR6XZ2rW9sqUyFOqblRlqR7Y1p2MomS7jLlCD13LtDR/h7imnqrBX8LLRvSkZslDVaw08j8UJ7MYUPHvrtR5327djmIfgS2frDrmpJmfKJcA1V3RFnDftC7ZU2E7M2F0nFN+b2zKw9aSLqhzRbO4FtgKn4Hu5QEcT5whz7jLMSCZoFP91q32lSopJIZf39PtznxxGimttI1LW+lzH42qUfRLUnLp0PUlqgyXGxdLtajyIvmpFupb0vm9p1336QohwYyvI2NSdHn/wXJ8HIRZbStrUAwenF3hEwD+dT5eYXv54phkpMg25RszFV1lGCw53SE0PpCl1Qj+TY6kRCqRNyvqxJA3ywdWnFY2Dm/QtXVRNtRf1pkhnCL1X9fI5Bj3X3YV+TQCuKQavKX8rMk+XGxAmjAyKZS109CSaNsaXe2rSQQ4SMowzbw8EcUnN9VbG9/JgmDUOu6KCwJtu4q9gzra1kuxyrlCDrO6cn5ELfLau/cKGIbMbxjklqkFg/1/SlWbEGxGohqPBnRRWQWs88sUXEgTfMdCyflnfjJ+Ofauorx+t/lTZfyrGN2N0kZgrdhv8EE=", "algid:sign:RSA:digest-PKCS1v15:SHA512": "CBYAi7jv30XmIPh9BnGm2aSi3qjj2HZHFsFGiVmkGa8ETuR0FcRvuT1VG3/MoosSfKatOx8D76wM9OTneJQSiqqvFWCoygbwVjrQfPbFqFkwPD3OJWv1lDoeaId0RtqhURvVL2qUuH+wEfQhgFBTVePEcUmf8ocx4iVJHi6Mq4AYEpPoID7Zyf0v59K3DBEICYlafPrc4+LYCpNYRgSt2CjeiODyc1gEMLgFQF7l3knIjsUxkAEgu/9Tfxpx5Grr2Qjuq4tAKxJ7I+yf+IHG48cQKiD8j9xBGHDy7D+V/bkFX86kZpGcUEh08TzweEQBTCYgMjo5o+yENY38Q6XWdE4fNQrpyjS/APUm9nEgF6lkYY4U7uxjHO0f57XCxjetNc5HEGPKxG3qXaEwEGyfK5xGi+KHWkJNhBtuKfKOYQBXxy8Y7ah3sYND1oAWwmBgoeFMKhm5oPRD0wMueWjAyvq7PZfzmO3Wqk4S+AfuvBE3QfKIVWbzPMIWhYbHY0hZk9i3Bc/PWxYOvfWUjVAxOWW2QrfZPscQebTkJFqCujzXJepM78lZ9HpYWbBzY7YVyN5shOCe3SyADuaDltvTzTj43E5b0F/1ozhWFEbTyfOPNCNj0ZhmFu0PAeDhv6r0SUL0yt2l18wpyXj82217NLhoOZ1CtIylAV7uXIW72bE=", "algid:sign:RSA:message-PKCS1v15:SHA1": "rmFdxrNZFYAkFf40eblr9DqQJd6pX4DJmrYoL6fXcBGr97Dh7IuELYrpIUPa/197q3InQkT0ViwWYHDhrQIbFx4aqycyQW0rd+f44tZGd2YJOKybxfShx2tmHxL2U8vx+iEz59OfoMs9YAZvcj2RRFkJMhafaihJNwEJofFZZ42tLbj3CrCOpKOwi39oTikstLjaV9e3ToFFtNioT9tLKSSuK2wH9+YQLVRF9bqu6usSYDDrC/RhchWE1FP6uaQbdXrg+9LkwU7dV9lsqBIQcLwFwBqYJ7yqUUC10yVRFcWeA4Sqj0oBehuoG2ozwRlkUUnULUXl3DXMLJquAqT+L1QLtxNqfQyXQtbLmmL+i9gVkEbQrd+Uk3pWeiB5ajgS4YYKcJhwdxtEmWHs4QIGZCD8bKDWESBRfH79BRA4kPUEd9ATkR/Pnj/+X/8NNH9gwj95BhGiBpe/F0UjDRIa1S3xI1muU0tcvX2emG0ZKYYyZd7ei1ZSWl1KZuNDNTABhqDayLM7EsZholpW8/1+t9lOpOO92utTjm1M35UBIA5odRdbuZPUtMHx+e5K4c2l7n3cQZdkrievjlPc5D04r30JJHey3L0QT06X8kkjAyjbsMDBcuKwdkGNBaAlrfmFd6YOxVyiaXLqHwbmcjgtWDQsLRKEZdLRFGcIsmH9B54=", "algid:sign:RSA:message-PKCS1v15:SHA224": "I4SK+LMQBpEU/XlK9pLSpFFLafx0q+pQGIMfpZPEAnUXL3FSCxZobbHasYSzyKvwqfmGXc4H7wxdeOSp1ADgVcN6e2YyPo22jShCIzS2mjMDVq/PmZp7tzpKGPhFa/+42uGaJYVMQX1V0YDGTljtpie/2xDWU4I8BfGdTyT2U1PtspyR+ldW1DxR7KzHUGzYvm141oLutXr80bMT3Pk9iMqYigcEu/o+lrUqam4n/HHZ0/PM6HZptkgyhaM3r5/4DqcuIpiThqxDzEt1Lbn80boz2S9xJ9u6eJ2jENq3DN/iD2BtRkKyh5NyLs/nC26afedV/dj7R7Fkuxq0HZ7+/CIM8L28++chluwjY2iQzFJUXJ8Wss5eU/ZHs60mWZmRh3180J6Wj8buH/T/7fE3J9ViGkPzbcENyiev7LU6uh2do5aKtxr3cjrx5zdOFR23E7q0ci5mY6OoGrWHCyZ9d4LAg+938HO05LtkbxZJUZD2DT5lAkbde6asGNmn47XHyYjTJ30Zxd9r1rRpcSNPtCyRiP6zLe/pQztmE+d78evB9vUGfmw26HXBKN621407AKdfGvNte9YLvJ8P/SvlJy1YQ1plWjzTkX/B3U5e9GkR/NSJP2wQ/OiXq/ns9eO1pXjesrPEB+eES2MTQX3UBuc0lnh1FJqB1FrCKJlCq28=", "algid:sign:RSA:message-PKCS1v15:SHA256": "azRVVXFadtDgsYjEkWddSycFMwdKl2FPLczbgdgeVLxWNltdHAibYSa0I/kKA5hl9M6dj8B+Di5zw71C2owKoLyJufhFGWmr7cNRQ8YzolBKnCm9AzZMCofMp86BBxuRSioWacmp1vMMRB9tG0LGSnlyVT/rJKNBoi8R6c2JfaFw3p87n3IyqhSaonAVdNCPAUp0Hi6iF2Hj+7kqVEbv0Az1DwHs7kAU7yFiJodKCsR9bh4Z6rXOG1oWcs02xTu35FlzzzBC+r6UUdhlAA5CEvzjGhein9v09LSP1Fks5CHbE0cgjW85mbJITPMMbXqGkM5LOgl0wynVPPZycVzoeelo7TKXsJqff6JzsZyFkmbLdX0Uimm7L3yABV6mgYQ0xcL9lvtvlNF+MOBjh6fWVn1jU5aq91Dx/exyR5QPg0u0jJkjFIq8vkitjuZ5Q0pZAmvmjYS/Mms/Sd4eP90Rq5s3n7v3BRXKr8rvMAd2x4LnHxHaV++k7uY1uSP+1En+3wp8HSmBs5rfoEiAkrGyHaYFJZCD1hLnwV7WtRNyI2cp3aP1P9Qh+QMliuJel0+SrdNlHzrouIL+Z/UmQ0QqZhEmuy3zkLZ+9XjtWJAxYQuNqBn0cMEx5BkZ1R+vwqIH2JzRhXDJMkhZiqbz8IjP25FahGUJzHt4uom0J6vbjp8=", "algid:sign:RSA:message-PKCS1v15:SHA384": "kEt8tqcYFA9lP95wZNkhBtx8sEf1tfp78PvgPj5bLEj5zO2dhC3ho8RV8076Ns7VqqtqGSdiLZ0xnNwwDUhgGerw1w23ar9ZxoQxYUM67SKIyfVS0l4TjnxDVGm/mREc3+O/v4NVjY+axo3FndsV8C5q0PIidt744GDVhheex82r7Cnp5gZdrObM8e3g2RIqJJUGEA+XKSwgofSspehh/tHkfgV122lUhf7SA9v6T3729NaxpWEzZCgQms+o+JQ4XoeNaCevMjGCRL2UZuhRelyFXiBwR469OJdwazEDO8QvrIdIU7a6WQMBi/kxDL8iLjRaZKCvLdvx9GueVgHoaSvEMJUhab6+v3GjzEbqs6BIRgyaJESYqjx3tU6WwvF98PWk9Vh9ZZ3D41oqt7sHVtDAtO+FWC7oasff7z1QY28qqZL4bt3KMIxFFbUpkKflGEQzZ28+d498FECfQSfu1be630D3O0p9S8Oxg1Y9QTlTXu0+7lU9zJWuSZGSetpNAewJEac50gfT3qpqQjKovEuzCEehGCqeJsQNU3WC7P+jfTr7JzXSCUNSuKwJQ3YHTwWNWIrIhXJb5otoDaKFd8fgB+QXruWCQQjGsb+kjXyCKsD6cfheH9PsuQVatbip5VbxnqLxcll3NapgR+kU4lAz+TilcpS/pXkbOqKdZZM=", "algid:sign:RSA:message-PKCS1v15:SHA512": "xnz4RUusIFwIaFiO63IIBgQ3GqyHsjJwnJ/a8B7T9z9YehKZa6Hh55bL3t1+7oKNAkK60H2nIprL7DZbS+bSoSkuDhihE9WQxqy4kt71zaqQIFu3FuFHji3ID1TYhZxEgf09NepVo7tQpYwOt9H6icc91mc2APrYiTlnjBuNGtm7vGixzXonhZcLAHLGjAhzqMqkx9LSpc6mc0DGqTHVC7++4syCznyf5T4JnE0ScgiMdLeFHeUiMG58HU8o9VOANWwQxdfDgl/saueaKhW3yHMS0ZvK2Ii07EiTjEhfBGBzb6xakdgH+ogEiqfqvGAN5OU09KnVRmWl4jDrk3d3xeQJl/LQvRt0M5Nbe3dw26HYDUNLf558fvYVuuMPi3mA9+6FDjQeJ0VakBujdHAG87a1x4pDurmreFIWGU3oJS0xC5WyHz1Tdh6IuPUVHCnM4V2fDW2Vq0rxgxz+KqHxtLrANjl6Jpe5b9Q/oC6VyWl5OHayu67xWYlI93BxCsKM9YN0kFJPI9ho6BzkEa2LowIJLKkmxjp5D/P/tMYCJRqNCtxatUj4aS5TLIw5SmrLEZA31bHYZ7xUoRmBqH4OnHd+GFc6KiAD4nTSznkSSlj8ybURjVHpOE65iafX0Q+c4DnvS4/0Lgu1PQ5as0uo+kCnRfLMYmt7iA8Ls6rGy9o=" ] ), "CryptoSwift RSA Keys are really cool! They support encrypting / decrypting messages, signing and verifying signed messages, and importing and exporting encrypted keys for use between sessions 🔐": ( encryptedMessage: [ "algid:encrypt:RSA:raw": "FoQR9BSodvPui0+rY1MGQ8nxqpcWjZRJ6fQ9Ck8pqFtHyaZNG5rTYZIS+xn09f2bOdldAn9TV7MyHAO794hoEtUwbBHChdsUDsmqoag2VOdfU7mpHF0qVl77YO+dAybc/CZj8zOTAepZyS2btelyCUnrwh9nidCO7R4q21nDgEYPwnXwCgnXG0/9fFbA6kPho08pVApfFihgUMnFA/EY4Kg0VNkkSNtk1CLcM4rZOb2uslhdEQfBxEr6Bo8ZQUXZGckRTm2JIsT3k2vewddt9yQMF3jjaKeQbbsmx0kMZiblcEpv0s/s+Yqwgelhtg68go0WHO4M6Ae0Ds231DLTo2ctwTPOznlECtxQ43s1vjdaO9KViB2SrBrm+798P85EvtBQMI6P19W7sTAQzPJjbhDjvodks4WS/apCpHUkM6lowiBgfKAqCWTNjlTa4MN6thV63HTMUVt+zbWMWd3/RuJjTUmwDxwdD5gMDE3J26GZFi/IS/qImPgo/fTvsgEqHt1EivNBhGZ+5G6MYo7MSEH2ftLz6ZfLQz0+wn1VEsLH8jsUAX5+KIar1luTRSdeRGpNmThZU/rxGQgQqEGjaIhBUmym6TD15aNVBIIl+yhlAUn0iCaknmedj7SsOsL/h8IVieq2kjVl9zCHQ8jl5DqwX3LnxWhVzAJAhUcwMjg=", "algid:encrypt:RSA:PKCS1": "LbjTnod9jalsiGR80n4slViv3auqAlqXL7+Te+ZnuQAWoInfjZjM4Wx4j2ITaW2swYJFAnB7N1EGVUdeMw0NHncTXXUoTQ/wuNhQefvFF6z9uFq4NJP2tXxhWc1H6/W4urXmlmKzbTAf0CKDbdiNjpnpXijg1hlkvFj/LOMn19TROpQfQyBVoBGIMDKndthZioMD0+8MUlThKLlH7f7BRpx2JQfn2KJ6f+YZfg9j9BHGWK0So8oaqTgwwPhPruzIMEJa5cFak3slss5gIGAFZZ5IjjnuL7OXH7uV+ntFo0Rv4kd56w6rrs6rE7o6iVNtYhP4Rzk5qUD2J0WTeXwj7tYEpGiNxNm5AQ4Bql0fxzVaV+zCtkJdyFzucLIl4/FOeuCIKAReA9Z1GvGVSbWoMxzrQVM4uOmmIcKCFLKMHsyW6kdtZXnvEl1BCJmkOdxTekmao02SZqWZh4yZV9fhq1lcy82OYSAD8Ou0dFf368HFFZmpv9rJZqOKKV05dWBFr7iCdrp3aXTwvs3G/uYsCP3Lng6mIIXIe+gzHR4+QzWHJsMZHlLVzGoYL2KLDC0SIjV+j9X31QalENIyTefmTrLxt3JwFhUNO2vF0w/8ZQuXDFEQswEB0zfharyJL1WFUOZ6uI/BEataICJ0Gv20lcPktAZx8Tsy2G4op0LTs20=" ], signedMessage: [ "algid:sign:RSA:raw": "wvvDbby0xhUBI5srmt3pF1TB9UH8xQwm1grHPha3MKCjp1m9wzJGBScUz/nFotYY/w+sbirOe+UQeTsk96QU+iAURvvEF46n8ACXw7vThlf1j8+EJyWrfSyPvxcZfUP/4wNKAORPhHreUYM5Q6xASdhporadi8ITVKlch5QSvJxUH7wy6YDt/34z16C6OzoUPICJXy/b8q98Cf+xK4/es0k+z6Bt6cQDFYyEK+OUJm9HD588Mq0gAuteS7mRQqGL2LHDA0fKOX0ptSU6vNOSv9GAuflsNCSAPxRNkOhHXN3dWDCrM96AJM9bQGvxnQWlbQf+yVnf5tClXlPqZcWZEN/I4dR2KFcg5OQx0pmudJ9AxcQFfaiyMw0b79rIcbJIb6vHWmz7fS/dNq1bvjXxPeOM+ahR91xqLENbphGt4y8MXZesGQjP3POw9YBL4XrUHOiTGhMr2SWJR569yUzglWNfnKFHl66HaaZrS688spbd+9f6rAxsyUaSZmcd43/CJjetpgEmHqu3E9k4Hq2Nm2NyhSiV7vNaiceCyF9yXMTDKHd7xAmDcs4wQyBXwXcFaJwFbWyEjUwXvumaq0eyM5Vs5u4NIcpo16FHMvHsu3wbI39ze7AK7jjD45STq6DJsJklp5WiV5WYv+2xDamZGi06XJmPaI2XnH+DrsiDqgg=", "algid:sign:RSA:digest-PKCS1v15": "aO5KdePNBsIJrolKleGat1/ZG1vqSHdocVznwvL96iLzxtr58I4IDO23P1U8/fsxz8HwDRRJoX/YvyZYRm8p+s1MO4stFZT6hOS2wCQx4z56JKFEzuld1rKSnUIppoxECQVBiQr3+xMb6jKX4eKPh42iN5e7x4Z0dQLk8cr6KfQFXJ8n7Hwz5154txDq/ZF0Jqbikwmg/yKsSWh1pecNkmel/PEgvP6HcAuuZx11QSu4U/P2psDngMV5AmuAeBEsd8cw7dmlRedUbNYTGk3FMEYL2q5lwigXr5uiwBvG8pBRtzX0r+TWRLk3x3i82dTEBID5FG2K5IIqsnqTyxvzspD5pePlc7v2JC61JcKIfWk/VAgSgAQbSdBbfpUj3XR3mBaWKjLBVTAGDHRLWFTgVnvcuC4hUmhUvpo7kRO9+c3XXAP0f+E3Zd3T3Cf+uhslB7mfmq1ctdg+zMNky9eBVbznWDDi3vVj/ase8ANTY0hHFXQfnDWfTpbPpJLYGK+SJuIyWzBxsOasPU6kSbN7nBgGUUnRSqFNWKpHfuHVT89nwDpPt1ynJoXWYjyVZGZdd5X36HfRjDrGw5q1AJMofAi/T/gb4QcfyDdrBDax7b/P/fiJ2PGeh1f1WJgjKiCDJvqBI6+vpKquhk6aqJFR5Z5XTBZTXXsV7nkZXeKE+98=", "algid:sign:RSA:digest-PKCS1v15:SHA1": "", "algid:sign:RSA:digest-PKCS1v15:SHA224": "", "algid:sign:RSA:digest-PKCS1v15:SHA256": "", "algid:sign:RSA:digest-PKCS1v15:SHA384": "", "algid:sign:RSA:digest-PKCS1v15:SHA512": "", "algid:sign:RSA:message-PKCS1v15:SHA1": "mmZt44HAZatukr2IHHmkvPJZOlL2rmkQ1KVGemw4pkLy/ixWmVKpMP/AT1DeB8bfINxVfwopeyAUhgcmXQrbEc5tlgmlezEhMBgHt7kqa03oAzqbDRw+ebTFCWsFMIsNdNII8fC6xHGpyB2mldNaitRmgvdWn3lrmuW8/1pWlXn4IRyOVbO0JevqHCFB4916khXT84FDxG0iAKTqFIJMXD213MDfyxM9kh7JFdbE+EpFDEknbCdpudOBNWrPLBpZVLyeV2p9usZpE2YT1KYzzPoWIvwHZbGTjcz54cC3ZPiX+x4Eu9ErAmC1CdmxYU2jd6xrMur4oNDn8rfvqK/xCpt/f2O90U1UwEvWzGTNYgtFaVwVURaryOIWz7algY26V6GWwJY31mftaL5PriAOxkajitegHvk7irHV2AFfEXZq4aR0VnBf7ua6tfvy9j/acbE9+ag/gojUkycXvTImYlpvQANUd2nJH/4wwB+dsiZUSMvOfgQjtSc3Ih+uu9whxOAQ3RNoYgvNbi4A8U1jflzA9aWo+Rfon4+wm/tuGB9NXn9ik0e7JeDJAWxhAmXW7AhPWpqfujS3kwgkb/Rm7W06r2+2xS3woCl+SST20nUu+/rcDsYUrwfS8SAiWQI69j1ukdZmgL13iK5Ah3sypNaj8Yx/0Y8S+E78LqzxKJg=", "algid:sign:RSA:message-PKCS1v15:SHA224": "bwSdwF2gSkYLR1ji1kDRFQKXSwcO625TcqTSLdw+nGpYZKR/6UCxD0OpIYGfOwa2Pzp1FApqNVJlGO2jXYFpXKQPsUm1RhrB87t0NE2pKuEo/Bb2ekC8kIXk1NloKSef0fMR01EbfKOsIJvJSIf7E5dXf9p4c+JnWaMzJ94EHQGJlrlSjDaiQu485dGArwOiMU3ZI/C3XqL0raYh6iOclKhU1Wzn38F9KnReHYC+I5+fld9L4zAjoigmvHUVJ8yQRvdUUauh5gatuIOl2W03qR25Tstv86sF1j7PzFYf2hYTRvCqzQ814hC3/Oh9hAi1rO7JHl8ntXcIi6YpiJxi4fztbbESTz0Mnd0Hq8PXWPIkCZjP4w0voJ73tuQf3Ogfe92L4Mb1Mzb1CquD7moBEQkHeq1S3B6uCdNG3e8KRGxS3e5fgqvTYmlSUrCbBh2qoEEEOIaqjVrx+rUqUMEQwbi+pFQqM2sRUjX0kEMRTNx6ZJg/iM1fh6XqYBmSVz7ZSub1hoCZxPudQXRkar46A+kLsErr6sZRrXXG4wZqqjHUMRmTz7m1VEY9chddanmX3na3E3EJQH5Qw6oOBRVrLPyeH9ov1EAj80ZauNpZaPl+FobEF1PS1v0BKfVcUXwtD/ZqdAbSJomSoWets93UtEPHv9F+msWJEU68vR6pQ7Q=", "algid:sign:RSA:message-PKCS1v15:SHA256": "Z2i9kWJBBTNccpZ27eB50h4jXGsTmjttJjbHZFpLeoJTLHe/VXt0UljlqRXoxkTi5gpJyFTA8wNRiekXBDZIILq3Od1AQR9/kRnx9VEhiXMJvQ8op6yVwI4w+kAroIIalLNGOSgPTjUNltj1l186UKJ0LM7SqeTuytEJJYJp8go8wC0ncU80Q1cl4CkSZQXP8y0WvJctguJFBIm2dg1/f2UF6HQBjyP4La35pXf3gfLJRZGf9fSkUlUpfpJvbdgc843saxfTyzvXQ7+YEk1zwEnRw62qp4l+A52fq1grJ8TwLMlRbn0YLEn76Kn8fWfkl3mlQu5ykfsLwqgpsUOndNjTATGSEc2qkxadTSJCJTaHeiW2UWmz+k6Blcy/+HCYc663zQxs/bV8qeoqrLapSdkDLBHYyr0C0cYuiM/xp6INITh4ryruiwA1zCiKv0hLKbT8r30mkwSfDxpal3VElOYIWsqA09oO0sk4g6bhByHWF4yg0Youx+yf1nQeQdHS1I7W86qXZCOJEVf/XNK/GZj7WOXkrt+QtYkv2DS2mAwF16Qlijcl4fBjpi+A9dezVEP/5celKdgSLOh5rtXlrQLdAv/qIqiO2r18IsJQplZdFOeR+TGt5x0QERt7EMEix5//pAEkhhWM7sCfUuLGFviWlX0GH2ZIt7qriEmASXk=", "algid:sign:RSA:message-PKCS1v15:SHA384": "hRh6hS1J6J5fXiBwnuZRwZ3ilXeYpvP8PSYxyI8+iKbS0Td7jXXLZqGK8NC+3YAwo9i/fbLcOmqqsPma7fVrmwfaqdNMcbOMF1Ifxvw0CPlski/K4VmEaI5h+N9kOMdes7TrZW1ZvqGbt82i9YuZY+nW9NBNpwlKWNd8LfIcLdqAtl8CgBgLv5qVminhws1BZPdFmQnZtE2venak7l+QBk1mXR/CAmZbMc+sKLru9WMRIBJO2Y+RGuEXtY6aGeghC+lEMejlP8SO8dDK3t9guYJTrHnUVmiamNL0qshYNBtxP0v67JnhbxFwZaWCITvzuGAfBvPVqiP/u0PuoIVQpvCsK6bdfs0xrXpvqWGpO952VZfmevu6XthLPI2rNPqncvPIX6hpMmWCUpVjVl8jW/mGQUIYyrlevCGe+0waHU1pgVGENd1vFCJ4aZ0RQOD5c68Rc1au9+5RkaoV4SvQvnf6yo1OpTMmWPrRTVbeLF5ke3cNMvNHEtoBoSLcyaJoNXWoWwN2rhkJ17WqCaJE7TJUtSxnmoAP8D0E+58kCwLTx3iOcuGSqC9cI6Yh8icigoD2eUVK8M1zrHbpX5tOqt9myQCXP9zu3xwU+DuzhxY3xwpI2LUAmvg215/4elEH5gYzSpQqDDINUWwykcG0sAsr9AZUAzLuBcxEIRkORxI=", "algid:sign:RSA:message-PKCS1v15:SHA512": "YDOCicIPMG7SRzkWybBnWXrDUBvc3I/N5cLDi41FaTwuFnnKSPZXmFKtYwsBJJEEr6dwtgJLJOVcqBShYW13XmOJWmtFqptCKxiS8K8ar9/CDaf0fnZLx3tYLqndi465ytbnGiDpcEy7uMOeKbyz744Vj4e8ZTLmADPZ1fG7IDvjfpJMVyKctus/elzFnKd9Xkczf7/drDjuQ9WejCbN/mTJblYFzY4PKmeukJl1LWcSw+jrsD4LAuIsLatpu2LjJK9W/RoGrzrR0rOk0xZCAA5m7BMnlr7vvDiSxH5Brt5CZ8UImrBgCV+Npl36m4aBlLUlGCQvMbYoUQa4oCoJsbwUHMnVSiRFxVGFBpkUjcxY7/6fvBsFZ2+sHY+nADrpAxlMRrq7mt6bZVTUFyQtCku2Un2We9XmTDIYEFZh3p+z44jLhdy1JFlAkgavVUjwDQA2GsdE2u/Hq3GiTAPx6CtJ1KG/SDqovxlIs+ImmYcWcgQcXCjVANjG3YnS9XIJXhF75TjVy+ooyxlATg1giNUzPHkVjovqf/2GcMNHotHumb98vafLXXSJXctErlP4ubk8ZHFtj09m5xrHXNm96B3DkOZWiuJ12bCMP1eSM2z8Wflq9+WUDti6DMb8O2NxxfVK5zh6cssTZrsUKH4AsSETxIE3sZJrWEDs2vJDVPA=" ] ) ] ) } } ================================================ FILE: Tests/CryptoSwiftTests/RabbitTests.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import XCTest @testable import CryptoSwift class RabbitTests: XCTestCase { func testInitialization() { var key = Array(repeating: 0, count: Rabbit.keySize - 1) var iv: Array? XCTAssertThrowsError(try Rabbit(key: key, iv: iv)) key = Array(repeating: 0, count: Rabbit.keySize + 1) XCTAssertThrowsError(try Rabbit(key: key, iv: iv)) key = Array(repeating: 0, count: Rabbit.keySize) XCTAssertNotNil(try Rabbit(key: key, iv: iv)) iv = Array(repeating: 0, count: Rabbit.ivSize - 1) XCTAssertThrowsError(try Rabbit(key: key, iv: iv)) iv = Array(repeating: 0, count: Rabbit.ivSize) XCTAssertNotNil(try Rabbit(key: key, iv: iv)) } func testRabbitWithoutIV() { // Examples from Appendix A: Test Vectors in http://tools.ietf.org/rfc/rfc4503.txt let cases: [(Array, Array)] = [ // First case ( [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [ 0xb1, 0x57, 0x54, 0xf0, 0x36, 0xa5, 0xd6, 0xec, 0xf5, 0x6b, 0x45, 0x26, 0x1c, 0x4a, 0xf7, 0x02, 0x88, 0xe8, 0xd8, 0x15, 0xc5, 0x9c, 0x0c, 0x39, 0x7b, 0x69, 0x6c, 0x47, 0x89, 0xc6, 0x8a, 0xa7, 0xf4, 0x16, 0xa1, 0xc3, 0x70, 0x0c, 0xd4, 0x51, 0xda, 0x68, 0xd1, 0x88, 0x16, 0x73, 0xd6, 0x96 ] ), // Second case ( [0x91, 0x28, 0x13, 0x29, 0x2e, 0x3d, 0x36, 0xfe, 0x3b, 0xfc, 0x62, 0xf1, 0xdc, 0x51, 0xc3, 0xac], [ 0x3d, 0x2d, 0xf3, 0xc8, 0x3e, 0xf6, 0x27, 0xa1, 0xe9, 0x7f, 0xc3, 0x84, 0x87, 0xe2, 0x51, 0x9c, 0xf5, 0x76, 0xcd, 0x61, 0xf4, 0x40, 0x5b, 0x88, 0x96, 0xbf, 0x53, 0xaa, 0x85, 0x54, 0xfc, 0x19, 0xe5, 0x54, 0x74, 0x73, 0xfb, 0xdb, 0x43, 0x50, 0x8a, 0xe5, 0x3b, 0x20, 0x20, 0x4d, 0x4c, 0x5e ] ), // Third case ( [0x83, 0x95, 0x74, 0x15, 0x87, 0xe0, 0xc7, 0x33, 0xe9, 0xe9, 0xab, 0x01, 0xc0, 0x9b, 0x00, 0x43], [ 0x0c, 0xb1, 0x0d, 0xcd, 0xa0, 0x41, 0xcd, 0xac, 0x32, 0xeb, 0x5c, 0xfd, 0x02, 0xd0, 0x60, 0x9b, 0x95, 0xfc, 0x9f, 0xca, 0x0f, 0x17, 0x01, 0x5a, 0x7b, 0x70, 0x92, 0x11, 0x4c, 0xff, 0x3e, 0xad, 0x96, 0x49, 0xe5, 0xde, 0x8b, 0xfc, 0x7f, 0x3f, 0x92, 0x41, 0x47, 0xad, 0x3a, 0x94, 0x74, 0x28 ] ) ] let plainText = Array(repeating: 0, count: 48) for (key, expectedCipher) in cases { let rabbit = try! Rabbit(key: key) let cipherText = try! rabbit.encrypt(plainText) XCTAssertEqual(cipherText, expectedCipher) XCTAssertEqual(try! rabbit.decrypt(cipherText), plainText) } } func testRabbitWithIV() { // Examples from Appendix A: Test Vectors in http://tools.ietf.org/rfc/rfc4503.txt let key = Array(repeating: 0, count: Rabbit.keySize) let cases: [(Array, Array)] = [ ( [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], [ 0xc6, 0xa7, 0x27, 0x5e, 0xf8, 0x54, 0x95, 0xd8, 0x7c, 0xcd, 0x5d, 0x37, 0x67, 0x05, 0xb7, 0xed, 0x5f, 0x29, 0xa6, 0xac, 0x04, 0xf5, 0xef, 0xd4, 0x7b, 0x8f, 0x29, 0x32, 0x70, 0xdc, 0x4a, 0x8d, 0x2a, 0xde, 0x82, 0x2b, 0x29, 0xde, 0x6c, 0x1e, 0xe5, 0x2b, 0xdb, 0x8a, 0x47, 0xbf, 0x8f, 0x66 ] ), ( [0xc3, 0x73, 0xf5, 0x75, 0xc1, 0x26, 0x7e, 0x59], [ 0x1f, 0xcd, 0x4e, 0xb9, 0x58, 0x00, 0x12, 0xe2, 0xe0, 0xdc, 0xcc, 0x92, 0x22, 0x01, 0x7d, 0x6d, 0xa7, 0x5f, 0x4e, 0x10, 0xd1, 0x21, 0x25, 0x01, 0x7b, 0x24, 0x99, 0xff, 0xed, 0x93, 0x6f, 0x2e, 0xeb, 0xc1, 0x12, 0xc3, 0x93, 0xe7, 0x38, 0x39, 0x23, 0x56, 0xbd, 0xd0, 0x12, 0x02, 0x9b, 0xa7 ] ), ( [0xa6, 0xeb, 0x56, 0x1a, 0xd2, 0xf4, 0x17, 0x27], [ 0x44, 0x5a, 0xd8, 0xc8, 0x05, 0x85, 0x8d, 0xbf, 0x70, 0xb6, 0xaf, 0x23, 0xa1, 0x51, 0x10, 0x4d, 0x96, 0xc8, 0xf2, 0x79, 0x47, 0xf4, 0x2c, 0x5b, 0xae, 0xae, 0x67, 0xc6, 0xac, 0xc3, 0x5b, 0x03, 0x9f, 0xcb, 0xfc, 0x89, 0x5f, 0xa7, 0x1c, 0x17, 0x31, 0x3d, 0xf0, 0x34, 0xf0, 0x15, 0x51, 0xcb ] ) ] let plainText = Array(repeating: 0, count: 48) for (iv, expectedCipher) in cases { let rabbit = try! Rabbit(key: key, iv: iv) let cipherText = try! rabbit.encrypt(plainText) XCTAssertEqual(cipherText, expectedCipher) XCTAssertEqual(try! rabbit.decrypt(cipherText), plainText) } } } extension RabbitTests { static func allTests() -> [(String, (RabbitTests) -> () -> Void)] { let tests = [ ("testInitialization", testInitialization), ("testRabbitWithoutIV", testRabbitWithoutIV), ("testRabbitWithIV", testRabbitWithIV) ] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/RabbitTestsPerf.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import XCTest @testable import CryptoSwift class RabbitTestsPerf: XCTestCase { func testRabbitPerformance() { let key: Array = Array(repeating: 0, count: Rabbit.keySize) let iv: Array = Array(repeating: 0, count: Rabbit.ivSize) let message = Array(repeating: 7, count: (1024 * 1024) * 1) measure { _ = try! Rabbit(key: key, iv: iv).encrypt(message) } } } extension RabbitTestsPerf { static func allTests() -> [(String, (RabbitTestsPerf) -> () -> Void)] { let tests = [ ("testRabbitPerformance", testRabbitPerformance) ] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/SHATestsPerf.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2017 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation import XCTest @testable import CryptoSwift final class SHATestsPerf: XCTestCase { static let len = 100000 let a = [UInt8](unsafeUninitializedCapacity: SHATestsPerf.len) { buf, count in for i in 0.. // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import XCTest @testable import CryptoSwift class Scrypt: XCTestCase { func testScrypt_0() { let password = Array("password".data(using: .ascii)!) let salt = Array("NaCl".data(using: .ascii)!) let deriver = try! CryptoSwift.Scrypt(password: password, salt: salt, dkLen: 64, N: 1024, r: 8, p: 16) let derived = try! deriver.calculate() let expected: [UInt8] = Array.init(hex: """ fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe 7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62 2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40 """.replacingOccurrences(of: " ", with: "").replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\t", with: "")) XCTAssertEqual(derived, expected) } func testScrypt_1() { let password = Array("pleaseletmein".data(using: .ascii)!) let salt = Array("SodiumChloride".data(using: .ascii)!) let deriver = try! CryptoSwift.Scrypt(password: password, salt: salt, dkLen: 64, N: 16384, r: 8, p: 1) let derived = try! deriver.calculate() let expected: [UInt8] = Array.init(hex: """ 70 23 bd cb 3a fd 73 48 46 1c 06 cd 81 fd 38 eb fd a8 fb ba 90 4f 8e 3e a9 b5 43 f6 54 5d a1 f2 d5 43 29 55 61 3f 0f cf 62 d4 97 05 24 2a 9a f9 e6 1e 85 dc 0d 65 1e 40 df cf 01 7b 45 57 58 87 """.replacingOccurrences(of: " ", with: "").replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\t", with: "")) XCTAssertEqual(derived, expected) } // Takes too long to run in debug mode! func testScrypt_2() { #if !DEBUG let password = Array("pleaseletmein".data(using: .ascii)!) let salt = Array("SodiumChloride".data(using: .ascii)!) let deriver = try! CryptoSwift.Scrypt(password: password, salt: salt, dkLen: 64, N: 1048576, r: 8, p: 1) let derived = try! deriver.calculate() let expected: [UInt8] = Array.init(hex: """ 21 01 cb 9b 6a 51 1a ae ad db be 09 cf 70 f8 81 ec 56 8d 57 4a 2f fd 4d ab e5 ee 98 20 ad aa 47 8e 56 fd 8f 4b a5 d0 9f fa 1c 6d 92 7c 40 f4 c3 37 30 40 49 e8 a9 52 fb cb f4 5c 6f a7 7a 41 a4 """.replacingOccurrences(of: " ", with: "").replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\t", with: "")) XCTAssertEqual(derived, expected) #endif } static let allTests = [ ("testScrypt_0", testScrypt_0), ("testScrypt_1", testScrypt_1), ("testScrypt_2", testScrypt_2) ] } ================================================ FILE: Tests/CryptoSwiftTests/ScryptTestsPerf.swift ================================================ // // CryptoSwift // // Copyright (C) 2014-2025 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import XCTest @testable import CryptoSwift class ScryptTestsPeft: XCTestCase { func testScryptPerformance() { let N = 16384 let password: Array = Array(repeating: 0, count: 32) let salt: Array = Array(repeating: 0, count: 32) measure { _ = try! CryptoSwift.Scrypt(password: password, salt: salt, dkLen: 64, N: N, r: 8, p: 1).calculate() } } } extension ScryptTestsPeft { static func allTests() -> [(String, (ScryptTestsPeft) -> () -> Void)] { let tests = [ ("testScryptPerformance", testScryptPerformance) ] return tests } } ================================================ FILE: Tests/CryptoSwiftTests/SignatureVerificationTests.swift ================================================ //// CryptoSwift // // Copyright (C) 2014-2023 Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import Foundation import XCTest @testable import CryptoSwift final class SignatureVerificationTests: XCTestCase { func testVerifySHA3Variants() { let testVectors: [SignatureVerificationTests.TestVector] = [ SignatureVerificationTests.testVectorMessage_pkcs1v15_SHA3_256, SignatureVerificationTests.testVectorMessage_pkcs1v15_SHA3_384, SignatureVerificationTests.testVectorMessage_pkcs1v15_SHA3_512, SignatureVerificationTests.testVectorDigest_pkcs1v15_SHA3_256, SignatureVerificationTests.testVectorDigest_pkcs1v15_SHA3_384, SignatureVerificationTests.testVectorDigest_pkcs1v15_SHA3_512 ] for testVector in testVectors { do { guard let publicDerData = Data(base64Encoded: testVector.publicDER) else { XCTFail("Corrupted data - publicDER") continue } let rsa = try RSA(publicDER: publicDerData.byteArray) guard let signedMessageData = Data(base64Encoded: testVector.signedMessage) else { XCTFail("Corrupted data - signedMessage") continue } let result = try rsa.verify(signature: signedMessageData.byteArray, for: testVector.originalMessage.bytes, variant: testVector.variant) XCTAssertTrue(result, "Verification failed for test vector with id `\(testVector.id)`") } catch let error { XCTFail("Failed with error \(error)") } } } } extension SignatureVerificationTests { struct TestVector { /// String to identify test vector. Used for logging purposes let id: String /// Public DER for RSA key let publicDER: String /// RSA signature variant let variant: RSA.SignatureVariant /// Original message that was signed let originalMessage: String /// Signed message let signedMessage: String } static let testVectorMessage_pkcs1v15_SHA3_256 = TestVector( id: "1", publicDER: "MIGJAoGBAJPTOQB0cqHPbrZO8Bnl77uFR8jgcYWmudETdRP57lCn/Q4v4Ga9OTqTkfbzX7DKq4WrrcPkx6/u4U4EVS6y7jyuq3Qn4VZMQPKiMiqRyRKhNKfC0i8SpMEhnIXGl824bi/YfV6arz0gicl24dP8C+HsO+WJGa7gtRs2d8hY2s+NAgMBAAE=", variant: .message_pkcs1v15_SHA3_256, originalMessage: "CryptoSwift Test", signedMessage: "IOIA/8NgoLVwtfto5Lnea7GLBXMddCAgQFBt38HVJpbEtuEcmu8uFs4sJuAHalH1iIe/cGPrwASRM94fSDKzuQ7XNX2Dwt8DBzu9BlAtEWq9GUSL/6DED0xJfqrl6G5rh+RRk9YYIk3TeI9H4HzsmIDFjp5hxFu0SedoR5DzEVM=" ) static let testVectorMessage_pkcs1v15_SHA3_384 = TestVector( id: "2", publicDER: "MIGJAoGBAJPTOQB0cqHPbrZO8Bnl77uFR8jgcYWmudETdRP57lCn/Q4v4Ga9OTqTkfbzX7DKq4WrrcPkx6/u4U4EVS6y7jyuq3Qn4VZMQPKiMiqRyRKhNKfC0i8SpMEhnIXGl824bi/YfV6arz0gicl24dP8C+HsO+WJGa7gtRs2d8hY2s+NAgMBAAE=", variant: .message_pkcs1v15_SHA3_384, originalMessage: "CryptoSwift Test", signedMessage: "J1qAdFj7iwlW6Mhyf5MfG2CN7BeUjKCFeCunBs2Hginwpcz/YfJgzNpGA93T+RBR4kLVuhs3OVILhwaMnTbgsMVNz0xLoZ5oegRADXDT1Ln3WuTUuqQH+RiMSILelgaHsU4fjj7jCC8wLFA2DtYm7aje1HF3ZRc/9SQSTREM5Gw=" ) static let testVectorMessage_pkcs1v15_SHA3_512 = TestVector( id: "3", publicDER: "MIGJAoGBAJPTOQB0cqHPbrZO8Bnl77uFR8jgcYWmudETdRP57lCn/Q4v4Ga9OTqTkfbzX7DKq4WrrcPkx6/u4U4EVS6y7jyuq3Qn4VZMQPKiMiqRyRKhNKfC0i8SpMEhnIXGl824bi/YfV6arz0gicl24dP8C+HsO+WJGa7gtRs2d8hY2s+NAgMBAAE=", variant: .message_pkcs1v15_SHA3_512, originalMessage: "CryptoSwift Test", signedMessage: "KMmRIptAPCZV7I/6gRN6wUQekRm+sxXWtoAyxC7PPiSBNd9XJTVVrEUnEfpnupI6uum+r9YxAT5Ha0S5XrYlojHZFLW3gZHLAKmRBushg8YRfqK68cDLYBshuqBlf5nuQZDU+7LTBh6Jnup2rGbQj1Bra9X9Hl9uZmoPY8Uoh/g=" ) static let testVectorDigest_pkcs1v15_SHA3_256 = TestVector( id: "4", publicDER: "MIGJAoGBAJPTOQB0cqHPbrZO8Bnl77uFR8jgcYWmudETdRP57lCn/Q4v4Ga9OTqTkfbzX7DKq4WrrcPkx6/u4U4EVS6y7jyuq3Qn4VZMQPKiMiqRyRKhNKfC0i8SpMEhnIXGl824bi/YfV6arz0gicl24dP8C+HsO+WJGa7gtRs2d8hY2s+NAgMBAAE=", variant: .digest_pkcs1v15_SHA3_256, originalMessage: "CryptoSwift Test", signedMessage: "Oj3CBwMQIEGrQwFuqIXklqOJG6pdaS5Kjal+sAKoMvEzXCB0h8K8w9YNt/XIOD9fJXdUaG0XR6RB8eEQxh/u6pYZPVUwssyA//FUjWLgKOecNkaca+EK98iIkivjVdEGK7yVhcQHJF19EfpZahVWWlEUCT02g8niomkWUHWIlo8=" ) static let testVectorDigest_pkcs1v15_SHA3_384 = TestVector( id: "5", publicDER: "MIGJAoGBAJPTOQB0cqHPbrZO8Bnl77uFR8jgcYWmudETdRP57lCn/Q4v4Ga9OTqTkfbzX7DKq4WrrcPkx6/u4U4EVS6y7jyuq3Qn4VZMQPKiMiqRyRKhNKfC0i8SpMEhnIXGl824bi/YfV6arz0gicl24dP8C+HsO+WJGa7gtRs2d8hY2s+NAgMBAAE=", variant: .digest_pkcs1v15_SHA3_384, originalMessage: "CryptoSwift Test", signedMessage: "ZCn19KmnT/QdzcNm077uopZeIxkR5EECX0po2QypPTYorYa9dGTm3nKR0mMr/G2C7ukrR2a8j5WPf4hXi1rlzOoFNufpbyQB33I9INleN7FjASmoxFcw6TyFNeMPN+TwKj9MVTEkZ7HtPL0bBsD8E08eRCDwk3UYdUjcvZcOdzw=" ) static let testVectorDigest_pkcs1v15_SHA3_512 = TestVector( id: "6", publicDER: "MIGJAoGBAJPTOQB0cqHPbrZO8Bnl77uFR8jgcYWmudETdRP57lCn/Q4v4Ga9OTqTkfbzX7DKq4WrrcPkx6/u4U4EVS6y7jyuq3Qn4VZMQPKiMiqRyRKhNKfC0i8SpMEhnIXGl824bi/YfV6arz0gicl24dP8C+HsO+WJGa7gtRs2d8hY2s+NAgMBAAE=", variant: .digest_pkcs1v15_SHA3_512, originalMessage: "CryptoSwift Test", signedMessage: "bk1/rtzt64ZApavxPrUEnsG/tN7nN6ITV3NKY0IR1i/3S4bkxIMulRsBPINpksTAafxrSm6EsLAmOPrqjwGycqRjSRi8/S6roUE/TIno2dGfO5e4eVKCQtD6I+CHA0Xji3X1k627vaYZqpTMFuMk8serfjMTHFe46s6S+f/64as=" ) } ================================================ FILE: Tests/CryptoSwiftTests/XCTestManifests.swift ================================================ #if !canImport(ObjectiveC) import XCTest extension AESCCMTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__AESCCMTests = [ ("testAESCCMTestCase1", testAESCCMTestCase1), ("testAESCCMTestCase1Decrypt", testAESCCMTestCase1Decrypt), ("testAESCCMTestCase2", testAESCCMTestCase2), ("testAESCCMTestCase2Decrypt", testAESCCMTestCase2Decrypt), ("testAESCCMTestCase3", testAESCCMTestCase3), ("testAESCCMTestCase3Decrypt", testAESCCMTestCase3Decrypt), ("testAESCCMTestCase3DecryptPartial", testAESCCMTestCase3DecryptPartial), ("testAESCCMTestDVPT256", testAESCCMTestDVPT256), ] } extension AESTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__AESTests = [ ("testAESDecryptCBCWithPaddingPartial", testAESDecryptCBCWithPaddingPartial), ("testAESDecryptCTRSeek", testAESDecryptCTRSeek), ("testAESEncrypt", testAESEncrypt), ("testAESEncrypt2", testAESEncrypt2), ("testAESEncrypt3", testAESEncrypt3), ("testAESEncryptCBCNoPadding", testAESEncryptCBCNoPadding), ("testAESEncryptCBCWithPadding", testAESEncryptCBCWithPadding), ("testAESEncryptCBCWithPaddingPartial", testAESEncryptCBCWithPaddingPartial), ("testAESEncryptCFB", testAESEncryptCFB), ("testAESEncryptCFBLong", testAESEncryptCFBLong), ("testAESEncryptCTR", testAESEncryptCTR), ("testAESEncryptCTRIrregularLength", testAESEncryptCTRIrregularLength), ("testAESEncryptCTRIrregularLengthIncrementalUpdate", testAESEncryptCTRIrregularLengthIncrementalUpdate), ("testAESEncryptCTRStream", testAESEncryptCTRStream), ("testAESEncryptCTRZeroPadding", testAESEncryptCTRZeroPadding), ("testAESEncryptIncremental", testAESEncryptIncremental), ("testAESEncryptOFB128", testAESEncryptOFB128), ("testAESEncryptOFB256", testAESEncryptOFB256), ("testAESEncryptPCBC256", testAESEncryptPCBC256), ("testAESGCMTagLengthCombined", testAESGCMTagLengthCombined), ("testAESGCMTagLengthCombined2", testAESGCMTagLengthCombined2), ("testAESGCMTagLengthDetached", testAESGCMTagLengthDetached), ("testAESGCMTestCase1", testAESGCMTestCase1), ("testAESGCMTestCase2", testAESGCMTestCase2), ("testAESGCMTestCase3", testAESGCMTestCase3), ("testAESGCMTestCase3Combined", testAESGCMTestCase3Combined), ("testAESGCMTestCase4", testAESGCMTestCase4), ("testAESGCMTestCase5", testAESGCMTestCase5), ("testAESGCMTestCase6", testAESGCMTestCase6), ("testAESGCMTestCase7", testAESGCMTestCase7), ("testAESGCMTestCaseIrregularCombined1", testAESGCMTestCaseIrregularCombined1), ("testAESGCMTestCaseIrregularCombined2", testAESGCMTestCaseIrregularCombined2), ("testAESWithWrongKey", testAESWithWrongKey), ("testIssue298", testIssue298), ("testIssue394", testIssue394), ("testIssue411", testIssue411), ] } extension AESTestsPerf { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__AESTestsPerf = [ ("testAESDecryptPerformance", testAESDecryptPerformance), ("testAESEncryptPerformance", testAESEncryptPerformance), ] } extension Access { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__Access = [ ("testAES", testAES), ("testArrayExtension", testArrayExtension), ("testAuthenticators", testAuthenticators), ("testBlowfish", testBlowfish), ("testChaCha20", testChaCha20), ("testChecksum", testChecksum), ("testCollectionExtension", testCollectionExtension), ("testDataExtension", testDataExtension), ("testDigest", testDigest), ("testIntExtension", testIntExtension), ("testPadding", testPadding), ("testPBKDF", testPBKDF), ("testRabbit", testRabbit), ("testRandomIV", testRandomIV), ("testStringExtension", testStringExtension), ("testStringFoundationExtension", testStringFoundationExtension), ("testUInt16Extension", testUInt16Extension), ("testUInt32Extension", testUInt32Extension), ("testUInt64Extension", testUInt64Extension), ("testUInt8Extension", testUInt8Extension), ("testUpdatable", testUpdatable), ] } extension BlowfishTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__BlowfishTests = [ ("testCBCZeroPadding", testCBCZeroPadding), ("testDecrypt", testDecrypt), ("testDecryptCFB415", testDecryptCFB415), ("testEncrypt", testEncrypt), ("testEncryptDecrypt", testEncryptDecrypt), ] } extension CBCMacTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__CBCMacTests = [ ("testMessageLength0", testMessageLength0), ("testMessageLength16", testMessageLength16), ("testMessageLength40", testMessageLength40), ("testMessageLength64", testMessageLength64), ] } extension CMACTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__CMACTests = [ ("testMessageLength0", testMessageLength0), ("testMessageLength16", testMessageLength16), ("testMessageLength40", testMessageLength40), ("testMessageLength64", testMessageLength64), ("testOMACTextVectors", testOMACTextVectors), ] } extension ChaCha20Poly1305Tests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__ChaCha20Poly1305Tests = [ ("test1", test1), ("test2", test2), ("test3", test3), ] } extension ChaCha20Tests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__ChaCha20Tests = [ ("testChaCha20", testChaCha20), ("testChaCha20EncryptPartial", testChaCha20EncryptPartial), ("testCore", testCore), ("testVector1Py", testVector1Py), ] } extension ChaCha20TestsPerf { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__ChaCha20TestsPerf = [ ("testChaCha20Performance", testChaCha20Performance), ] } extension DigestTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__DigestTests = [ ("testChecksum", testChecksum), ("testChecksumPerformance", testChecksumPerformance), ("testCRC16", testCRC16), ("testCRC32", testCRC32), ("testCRC32C", testCRC32C), ("testCRC32NotReflected", testCRC32NotReflected), ("testMD5", testMD5), ("testMD5Data", testMD5Data), ("testMD5Updates", testMD5Updates), ("testSHA1", testSHA1), ("testSHA1Updatable1", testSHA1Updatable1), ("testSHA1Updatable2", testSHA1Updatable2), ("testSHA2", testSHA2), ("testSHA3", testSHA3), ("testSHAPartialUpdates", testSHAPartialUpdates), ] } extension DigestTestsPerf { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__DigestTestsPerf = [ ("testMD5Performance", testMD5Performance), ("testSHA1Performance", testSHA1Performance), ] } extension ExtensionsTest { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__ExtensionsTest = [ ("testArrayInitHex", testArrayInitHex), ("testBytes", testBytes), ("testDataInit", testDataInit), ("testEmptyStringEncrypt", testEmptyStringEncrypt), ("testStringDecryptBase64", testStringDecryptBase64), ("testStringEncrypt", testStringEncrypt), ("testToHexStringPerformance", testToHexStringPerformance), ("testToUInt32Array", testToUInt32Array), ("testToUInt32Performance", testToUInt32Performance), ("testToUInt64Performance", testToUInt64Performance), ] } extension ExtensionsTestPerf { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__ExtensionsTestPerf = [ ("testArrayInitHexPerformance", testArrayInitHexPerformance), ] } extension HKDFTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__HKDFTests = [ ("testHKDF1", testHKDF1), ("testHKDF2", testHKDF2), ("testHKDF3", testHKDF3), ("testHKDF4", testHKDF4), ("testHKDF5", testHKDF5), ("testHKDF6", testHKDF6), ] } extension HMACTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__HMACTests = [ ("testMD5", testMD5), ("testSHA1", testSHA1), ("testSHA256", testSHA256), ("testSHA384", testSHA384), ("testSHA512", testSHA512), ] } extension OCBTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__OCBTests = [ ("testAESOCBWithRFC7253Tests", testAESOCBWithRFC7253Tests), ] } extension PBKDF { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__PBKDF = [ ("testPBKDF1", testPBKDF1), ("testPBKDF2", testPBKDF2), ("testPBKDF2Length", testPBKDF2Length), ] } extension PBKDFPerf { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__PBKDFPerf = [ ("testPerformance", testPerformance), ] } extension PaddingTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__PaddingTests = [ ("testISO78164_0", testISO78164_0), ("testISO78164_1", testISO78164_1), ("testISO78164_2", testISO78164_2), ("testPKCS7_0", testPKCS7_0), ("testPKCS7_1", testPKCS7_1), ("testPKCS7_2", testPKCS7_2), ("testZeroPadding1", testZeroPadding1), ("testZeroPadding2", testZeroPadding2), ] } extension Poly1305Tests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__Poly1305Tests = [ ("testIssue183", testIssue183), ("testPoly1305", testPoly1305), ] } extension RabbitTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__RabbitTests = [ ("testInitialization", testInitialization), ("testRabbitWithIV", testRabbitWithIV), ("testRabbitWithoutIV", testRabbitWithoutIV), ] } extension RabbitTestsPerf { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__RabbitTestsPerf = [ ("testRabbitPerformance", testRabbitPerformance), ] } extension SHATestsPerf { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__SHATestsPerf = [ ("testSHA1Performance", testSHA1Performance), ("testSHA2224Performance", testSHA2224Performance), ("testSHA2256Performance", testSHA2256Performance), ("testSHA2384Performance", testSHA2384Performance), ("testSHA2512Performance", testSHA2512Performance), ("testSHA3224Performance", testSHA3224Performance), ("testSHA3256Performance", testSHA3256Performance), ("testSHA3384Performance", testSHA3384Performance), ("testSHA3512Performance", testSHA3512Performance), ("testSHA3keccak224Performance", testSHA3keccak224Performance), ("testSHA3keccak256Performance", testSHA3keccak256Performance), ("testSHA3keccak384Performance", testSHA3keccak384Performance), ("testSHA3keccak512Performance", testSHA3keccak512Performance), ] } extension Scrypt { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__Scrypt = [ ("testScrypt_0", testScrypt_0), ("testScrypt_1", testScrypt_1), ("testScrypt_2", testScrypt_2), ] } extension ScryptTestsPeft { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__ScryptTestsPeft = [ ("testScryptPerformance", testScryptPerformance), ] } public func __allTests() -> [XCTestCaseEntry] { return [ testCase(AESCCMTests.__allTests__AESCCMTests), testCase(AESTests.__allTests__AESTests), testCase(AESTestsPerf.__allTests__AESTestsPerf), testCase(Access.__allTests__Access), testCase(BlowfishTests.__allTests__BlowfishTests), testCase(CBCMacTests.__allTests__CBCMacTests), testCase(CMACTests.__allTests__CMACTests), testCase(ChaCha20Poly1305Tests.__allTests__ChaCha20Poly1305Tests), testCase(ChaCha20Tests.__allTests__ChaCha20Tests), testCase(ChaCha20TestsPerf.__allTests__ChaCha20TestsPerf), testCase(DigestTests.__allTests__DigestTests), testCase(DigestTestsPerf.__allTests__DigestTestsPerf), testCase(ExtensionsTest.__allTests__ExtensionsTest), testCase(ExtensionsTestPerf.__allTests__ExtensionsTestPerf), testCase(HKDFTests.__allTests__HKDFTests), testCase(HMACTests.__allTests__HMACTests), testCase(OCBTests.__allTests__OCBTests), testCase(PBKDF.__allTests__PBKDF), testCase(PBKDFPerf.__allTests__PBKDFPerf), testCase(PaddingTests.__allTests__PaddingTests), testCase(Poly1305Tests.__allTests__Poly1305Tests), testCase(RabbitTests.__allTests__RabbitTests), testCase(RabbitTestsPerf.__allTests__RabbitTestsPerf), testCase(SHATestsPerf.__allTests__SHATestsPerf), testCase(Scrypt.__allTests__Scrypt), testCase(ScryptTestsPeft.__allTests__ScryptTestsPeft), ] } #endif ================================================ FILE: Tests/CryptoSwiftTests/XChaCha20Poly1305Tests.swift ================================================ // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import XCTest @testable import CryptoSwift class XChaCha20Poly1305Tests: XCTestCase { /// See: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha#appendix-A.3.1 func testRoundTrip() { do { let plaintext: Array = .init( hex: """ 4c616469657320616e642047656e746c656d656e206f662074686520636c6173 73206f66202739393a204966204920636f756c64206f6666657220796f75206f 6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73 637265656e20776f756c642062652069742e """.replacingOccurrences(of: "\n", with: "") ) let aad: Array = .init( hex: "50515253c0c1c2c3c4c5c6c7") let key: Array = .init( hex: "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f") let iv: Array = .init( hex: "404142434445464748494a4b4c4d4e4f5051525354555657") let encryptResult = try AEADXChaCha20Poly1305.encrypt( plaintext, key: key, iv: iv, authenticationHeader: aad ) XCTAssertEqual( encryptResult.cipherText.toHexString(), """ bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb 731c7f1b0b4aa6440bf3a82f4eda7e39ae64c6708c54c216cb96b72e1213b452 2f8c9ba40db5d945b11b69b982c1bb9e3f3fac2bc369488f76b2383565d3fff9 21f9664c97637da9768812f615c68b13b52e """.replacingOccurrences(of: "\n", with: "") ) XCTAssertEqual( encryptResult.authenticationTag.toHexString(), "c0875924c1c7987947deafd8780acf49" ) let decryptResult = try AEADXChaCha20Poly1305.decrypt( encryptResult.cipherText, key: key, iv: iv, authenticationHeader: aad, authenticationTag: encryptResult.authenticationTag ) XCTAssertEqual(decryptResult.plainText, plaintext) } catch { XCTFail(error.localizedDescription) } } static let allTests = [ ("Test Vector for AEAD_XCHACHA20_POLY1305", testRoundTrip) ] } ================================================ FILE: Tests/CryptoSwiftTests/XChaCha20Tests.swift ================================================ // // CryptoSwift // // Copyright (C) Marcin Krzyżanowski // This software is provided 'as-is', without any express or implied warranty. // // In no event will the authors be held liable for any damages arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: // // - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. // - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. // - This notice may not be removed or altered from any source or binary distribution. // import XCTest @testable import CryptoSwift final class XChaCha20Tests: XCTestCase { /// See: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha#section-2.2.1 func testHChaCha20BlockFunction() { let key: Array = .init( hex: "00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f".replacingOccurrences(of: ":", with: "")) let counter: Array = .init( hex: "00:00:00:09:00:00:00:4a:00:00:00:00:31:41:59:27".replacingOccurrences(of: ":", with: "")) XCTAssertEqual( XChaCha20.hChaCha20(key: key, nonce: counter).toHexString(), """ 82413b42 27b27bfe d30e4250 8a877d73 a0f9e4d5 8a74a853 c12ec413 26d3ecdc """.replacingOccurrences(of: " ", with: "").replacingOccurrences(of: "\n", with: "") ) } // See: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha#appendix-A.3.2.1 let plaintext: Array = .init( hex: """ 5468652064686f6c65202870726f6e6f756e6365642022646f6c652229206973 20616c736f206b6e6f776e2061732074686520417369617469632077696c6420 646f672c2072656420646f672c20616e642077686973746c696e6720646f672e 2049742069732061626f7574207468652073697a65206f662061204765726d61 6e20736865706865726420627574206c6f6f6b73206d6f7265206c696b652061 206c6f6e672d6c656767656420666f782e205468697320686967686c7920656c 757369766520616e6420736b696c6c6564206a756d70657220697320636c6173 736966696564207769746820776f6c7665732c20636f796f7465732c206a6163 6b616c732c20616e6420666f78657320696e20746865207461786f6e6f6d6963 2066616d696c792043616e696461652e """.replacingOccurrences(of: "\n", with: "")) let key: Array = .init(hex: "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f") let iv: Array = .init(hex: "404142434445464748494a4b4c4d4e4f5051525354555658") let expectedResult0 = """ 4559abba4e48c16102e8bb2c05e6947f50a786de162f9b0b7e592a9b53d0d4e9 8d8d6410d540a1a6375b26d80dace4fab52384c731acbf16a5923c0c48d3575d 4d0d2c673b666faa731061277701093a6bf7a158a8864292a41c48e3a9b4c0da ece0f8d98d0d7e05b37a307bbb66333164ec9e1b24ea0d6c3ffddcec4f68e744 3056193a03c810e11344ca06d8ed8a2bfb1e8d48cfa6bc0eb4e2464b74814240 7c9f431aee769960e15ba8b96890466ef2457599852385c661f752ce20f9da0c 09ab6b19df74e76a95967446f8d0fd415e7bee2a12a114c20eb5292ae7a349ae 577820d5520a1f3fb62a17ce6a7e68fa7c79111d8860920bc048ef43fe84486c cb87c25f0ae045f0cce1e7989a9aa220a28bdd4827e751a24a6d5c62d790a663 93b93111c1a55dd7421a10184974c7c5 """.replacingOccurrences(of: "\n", with: "") func testXChaCha20() { do { let actualResult0 = try XChaCha20(key: key, iv: iv, blockCounter: 0).encrypt(self.plaintext).toHexString() XCTAssertEqual(actualResult0, self.expectedResult0) // See: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha#appendix-A.3.2.2 let actualResult1 = try XChaCha20(key: key, iv: iv, blockCounter: 1).encrypt(self.plaintext).toHexString() XCTAssertEqual( actualResult1, """ 7d0a2e6b7f7c65a236542630294e063b7ab9b555a5d5149aa21e4ae1e4fbce87 ecc8e08a8b5e350abe622b2ffa617b202cfad72032a3037e76ffdcdc4376ee05 3a190d7e46ca1de04144850381b9cb29f051915386b8a710b8ac4d027b8b050f 7cba5854e028d564e453b8a968824173fc16488b8970cac828f11ae53cabd201 12f87107df24ee6183d2274fe4c8b1485534ef2c5fbc1ec24bfc3663efaa08bc 047d29d25043532db8391a8a3d776bf4372a6955827ccb0cdd4af403a7ce4c63 d595c75a43e045f0cce1f29c8b93bd65afc5974922f214a40b7c402cdb91ae73 c0b63615cdad0480680f16515a7ace9d39236464328a37743ffc28f4ddb324f4 d0f5bbdc270c65b1749a6efff1fbaa09536175ccd29fb9e6057b307320d31683 8a9c71f70b5b5907a66f7ea49aadc409 """.replacingOccurrences(of: "\n", with: "") ) } catch { XCTFail(error.localizedDescription) } } func testXChaCha20PartialEncryption() { do { let cipher = try XChaCha20(key: key, iv: iv) var ciphertext = Array() var encryptor = try cipher.makeEncryptor() try self.plaintext.batched(by: 8).forEach { chunk in ciphertext += try encryptor.update(withBytes: chunk) } ciphertext += try encryptor.finish() XCTAssertEqual(ciphertext.toHexString(), self.expectedResult0) } catch { XCTFail(error.localizedDescription) } } func testXChaCha20PartialDecryption() { do { let cipher = try XChaCha20(key: key, iv: iv) var plaintext = Array() var decryptor = try cipher.makeDecryptor() let ciphertext = Array(hex: expectedResult0) try ciphertext.batched(by: 8).forEach { chunk in plaintext += try decryptor.update(withBytes: chunk) } plaintext += try decryptor.finish() XCTAssertEqual(plaintext, self.plaintext) } catch { XCTFail(error.localizedDescription) } } static func allTests() -> [(String, (XChaCha20Tests) -> () -> Void)] { let tests = [ ("Test Vector for the HChaCha20 Block Function", testHChaCha20BlockFunction), ("Test Vectors for XChaCha20", testXChaCha20), ("XChaCha20 partial encryption", testXChaCha20PartialEncryption), ("XChaCha20 partial decryption", testXChaCha20PartialDecryption), ] return tests } } ================================================ FILE: Tests/LinuxMain.swift ================================================ import XCTest import CryptoSwiftTests var tests = [XCTestCaseEntry]() tests += CryptoSwiftTests.__allTests() XCTMain(tests) ================================================ FILE: Tests/TestsPerformance/XCTestManifests.swift ================================================ #if !canImport(ObjectiveC) import XCTest extension TestsPerformance { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` // to regenerate. static let __allTests__TestsPerformance = [ ("testExample", testExample), ("testPerformanceExample", testPerformanceExample), ] } public func __allTests() -> [XCTestCaseEntry] { return [ testCase(TestsPerformance.__allTests__TestsPerformance), ] } #endif ================================================ FILE: _config.yml ================================================ theme: jekyll-theme-minimal ================================================ FILE: config/CryptoSwift-Debug.xcconfig ================================================ #include "CryptoSwift-Shared.xcconfig" OTHER_SWIFT_FLAGS = $(inherited) -Xfrontend -debug-time-function-bodies SWIFT_COMPILATION_MODE = incremental SWIFT_OPTIMIZATION_LEVEL = -Onone SWIFT_ENFORCE_EXCLUSIVE_ACCESS = none ================================================ FILE: config/CryptoSwift-Release.xcconfig ================================================ #include "CryptoSwift-Shared.xcconfig" BITCODE_GENERATION_MODE = bitcode CLANG_USE_OPTIMIZATION_PROFILE = NO GCC_GENERATE_DEBUGGING_SYMBOLS = NO GCC_UNROLL_LOOPS = YES LLVM_LTO = YES SWIFT_DISABLE_SAFETY_CHECKS = YES SWIFT_ENFORCE_EXCLUSIVE_ACCESS = compile-time SWIFT_OPTIMIZATION_LEVEL = -O ================================================ FILE: config/CryptoSwift-Shared.xcconfig ================================================ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES APPLICATION_EXTENSION_API_ONLY = YES DYLIB_COMPATIBILITY_VERSION = 1 DYLIB_CURRENT_VERSION = 1 DYLIB_INSTALL_NAME_BASE = @rpath ENABLE_BITCODE = NO ENABLE_BITCODE[sdk=macosx*] = NO INSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Frameworks LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks INFOPLIST_FILE = Info.plist PRODUCT_BUNDLE_IDENTIFIER = com.krzyzanowskim.${PRODUCT_NAME:rfc1034identifier} PRODUCT_NAME = $(TARGET_NAME) SKIP_INSTALL = YES DEAD_CODE_STRIPPING = YES ================================================ FILE: config/CryptoSwift-Test.xcconfig ================================================ #include "CryptoSwift-Shared.xcconfig" ENABLE_TESTABILITY = YES STRIP_INSTALLED_PRODUCT = NO // Disable for tests. https://twitter.com/krzyzanowskim/status/1191515868401983489 BUILD_LIBRARY_FOR_DISTRIBUTION = NO COPY_PHASE_STRIP = NO ================================================ FILE: config/CryptoSwift-TestHostApp-Shared.xcconfig ================================================ // // CryptoSwift-TestHostApp-Shared.xcconfig // // Generated by BuildSettingExtractor on 02/04/2018 // https://github.com/dempseyatgithub/BuildSettingExtractor // CODE_SIGN_STYLE = Automatic CODE_SIGN_IDENTITY = iPhone Developer DEVELOPMENT_TEAM = HA4H7JURM8 PROVISIONING_PROFILE_SPECIFIER = ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES // Asset Catalog App Icon Set Name // // Name of an asset catalog app icon set whose contents will be merged into the // `Info.plist`. ASSETCATALOG_COMPILER_APPICON_NAME = // Info.plist File // // The project-relative path to the property list file that contains the `Info.plist` // information used by bundles. For details on information property list files, see // [Information Property List // Files](https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/ConfigFiles.html#//apple_ref/doc/uid/20002091-CJBJIEDH) // in [Runtime Configuration // Guidelines](https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPRuntimeConfig/000-Introduction/introduction.html). INFOPLIST_FILE = CryptoSwift-TestHostApp/Info.plist // Runpath Search Paths // // This is a list of paths to be added to the `runpath` search path list for the image // being created. At runtime, `dyld` uses the `runpath` when searching for dylibs whose // load path begins with `@rpath/`. See [Dynamic Library Programming // Topics](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/DynamicLibraries/000-Introduction/Introduction.html). LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks // Product Bundle Identifier // // A string that uniquely identifies the bundle. The string should be in reverse DNS // format using only alphanumeric characters (`A-Z`, `a-z`, `0-9`), the dot (`.`), and // the hyphen (`-`). This value is used as the `CFBundleIdentifier` in the `Info.plist` // of the built bundle. PRODUCT_BUNDLE_IDENTIFIER = test.CryptoSwiftTestHostApp // Base SDK // // The name or path of the base SDK being used during the build. The product will be // built against the headers and libraries located inside the indicated SDK. This path // will be prepended to all search paths, and will be passed through the environment to // the compiler and linker. Additional SDKs can be specified in the `ADDITIONAL_SDKS` // setting. SDKROOT = iphoneos SUPPORTED_PLATFORMS = iphonesimulator iphoneos COPY_PHASE_STRIP = NO ONLY_ACTIVE_ARCH = YES ================================================ FILE: config/CryptoSwift-TestHostApp-Test.xcconfig ================================================ // // CryptoSwift-TestHostApp-Test.xcconfig // // Generated by BuildSettingExtractor on 02/04/2018 // https://github.com/dempseyatgithub/BuildSettingExtractor // #include "CryptoSwift-TestHostApp-Shared.xcconfig" DEBUG_INFORMATION_FORMAT = dwarf-with-dsym ENABLE_NS_ASSERTIONS = NO MTL_ENABLE_DEBUG_INFO = NO SWIFT_OPTIMIZATION_LEVEL = -O VALIDATE_PRODUCT = YES ================================================ FILE: config/Project-Debug.xcconfig ================================================ #include "Project-Shared.xcconfig" COPY_PHASE_STRIP = NO GCC_DYNAMIC_NO_PIC = NO GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG=1 SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG METAL_ENABLE_DEBUG_INFO = YES ONLY_ACTIVE_ARCH = YES ENABLE_TESTABILITY = YES ================================================ FILE: config/Project-Release.xcconfig ================================================ #include "Project-Shared.xcconfig" CODE_SIGN_IDENTITY[sdk=macosx*] = Developer ID Application CLANG_USE_OPTIMIZATION_PROFILE = YES COPY_PHASE_STRIP = YES ENABLE_NS_ASSERTIONS = NO GCC_OPTIMIZATION_LEVEL = fast METAL_ENABLE_DEBUG_INFO = NO VALIDATE_PRODUCT = YES ================================================ FILE: config/Project-Shared.xcconfig ================================================ MARKETING_VERSION = 1.9.0 SUPPORTED_PLATFORMS = iphonesimulator iphoneos macosx appletvos watchos appletvsimulator watchsimulator xrsimulator xros SWIFT_COMPILATION_MODE = wholemodule SWIFT_VERSION = 5.0 TARGETED_DEVICE_FAMILY = 1,2,3,4 TVOS_DEPLOYMENT_TARGET = 11.0 IPHONEOS_DEPLOYMENT_TARGET = 11.0 MACOSX_DEPLOYMENT_TARGET = 10.13 WATCHOS_DEPLOYMENT_TARGET = 4.0 XROS_DEPLOYMENT_TARGET = 1.0 DEVELOPMENT_TEAM = //PROVISIONING_PROFILE = //PROVISIONING_PROFILE_SPECIFIER = CODE_SIGN_IDENTITY[sdk=macosx*] = Mac Developer CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer CODE_SIGN_IDENTITY[sdk=iphonesimulator*] = iPhone Developer CODE_SIGN_STYLE = Automatic PRODUCT_NAME = ${TARGET_NAME} CLANG_ANALYZER_NONNULL = YES CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE ALWAYS_SEARCH_USER_PATHS = NO CLANG_CXX_LANGUAGE_STANDARD = gnu++0x CLANG_CXX_LIBRARY = libc++ CLANG_ENABLE_MODULES = YES CLANG_ENABLE_OBJC_ARC = YES CLANG_ENABLE_OBJC_WEAK = YES CLANG_WARN__DUPLICATE_METHOD_MATCH = YES CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES CLANG_WARN_BOOL_CONVERSION = YES CLANG_WARN_COMMA = YES CLANG_WARN_CONSTANT_CONVERSION = YES CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR CLANG_WARN_EMPTY_BODY = YES CLANG_WARN_ENUM_CONVERSION = YES CLANG_WARN_INFINITE_RECURSION = YES CLANG_WARN_INT_CONVERSION = YES CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES CLANG_WARN_OBJC_LITERAL_CONVERSION = YES CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR CLANG_WARN_RANGE_LOOP_ANALYSIS = YES CLANG_WARN_STRICT_PROTOTYPES = YES CLANG_WARN_SUSPICIOUS_MOVE = YES CLANG_WARN_UNREACHABLE_CODE = YES CLANG_WARN_DOCUMENTATION_COMMENTS = YES CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE DEBUG_INFORMATION_FORMAT = dwarf DEFINES_MODULE = YES ENABLE_STRICT_OBJC_MSGSEND = YES GCC_C_LANGUAGE_STANDARD = gnu99 GCC_NO_COMMON_BLOCKS = YES GCC_WARN_64_TO_32_BIT_CONVERSION = YES GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR GCC_WARN_UNDECLARED_SELECTOR = YES GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE GCC_WARN_UNUSED_FUNCTION = YES GCC_WARN_UNUSED_LABEL = YES GCC_WARN_UNUSED_VARIABLE = YES CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES VERSION_INFO_PREFIX = VERSIONING_SYSTEM = apple-generic CURRENT_PROJECT_VERSION = 1 // XCFramework // Swift have (at least) 2 language dialects: With and without Library Evolution behave differently regarding enums. BUILD_LIBRARY_FOR_DISTRIBUTION = YES // Catalyst SUPPORTS_MACCATALYST = YES SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = NO ================================================ FILE: config/Tests-Shared.xcconfig ================================================ DEVELOPMENT_TEAM = CODE_SIGN_IDENTITY = CODE_SIGN_STYLE = Manual CODE_SIGNING_REQUIRED = NO HEADER_SEARCH_PATHS = $(inherited) includes/** LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks @loader_path/../Frameworks @executable_path/../Frameworks PRODUCT_BUNDLE_IDENTIFIER = com.krzyzanowskim.${PRODUCT_NAME:rfc1034identifier} OTHER_SWIFT_FLAGS = $(inherited) -Xfrontend -debug-time-function-bodies // Disable for tests. https://twitter.com/krzyzanowskim/status/1191515868401983489 BUILD_LIBRARY_FOR_DISTRIBUTION = NO MACOSX_DEPLOYMENT_TARGET = 10.15 INFOPLIST_FILE = Info.plist ================================================ FILE: config/Tests-Test.xcconfig ================================================ #include "Tests-Shared.xcconfig" COPY_PHASE_STRIP = NO ENABLE_NS_ASSERTIONS = NO ENABLE_TESTABILITY = YES GCC_OPTIMIZATION_LEVEL = fast GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG=1 CI=1 SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG SWIFT_DISABLE_SAFETY_CHECKS = YES SWIFT_OPTIMIZATION_LEVEL = -O METAL_ENABLE_DEBUG_INFO = NO ONLY_ACTIVE_ARCH = YES VALIDATE_PRODUCT = YES ================================================ FILE: scripts/build-framework.sh ================================================ #!/usr/bin/env bash set -e BASE_PWD="$PWD" SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" OUTPUT_DIR=$( mktemp -d ) COMMON_SETUP="-project ${SCRIPT_DIR}/../CryptoSwift.xcodeproj -scheme CryptoSwift -configuration Release -quiet SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES" # macOS DERIVED_DATA_PATH=$( mktemp -d ) xcrun xcodebuild build \ $COMMON_SETUP \ -derivedDataPath "${DERIVED_DATA_PATH}" \ -destination 'generic/platform=macOS' mkdir -p "${OUTPUT_DIR}/macos" ditto "${DERIVED_DATA_PATH}/Build/Products/Release/CryptoSwift.framework" "${OUTPUT_DIR}/macos/CryptoSwift.framework" rm -rf "${DERIVED_DATA_PATH}" # macOS Catalyst DERIVED_DATA_PATH=$( mktemp -d ) xcrun xcodebuild build \ $COMMON_SETUP \ -derivedDataPath "${DERIVED_DATA_PATH}" \ -destination 'generic/platform=macOS,variant=Mac Catalyst' mkdir -p "${OUTPUT_DIR}/maccatalyst" ditto "${DERIVED_DATA_PATH}/Build/Products/Release-maccatalyst/CryptoSwift.framework" "${OUTPUT_DIR}/maccatalyst/CryptoSwift.framework" rm -rf "${DERIVED_DATA_PATH}" # iOS DERIVED_DATA_PATH=$( mktemp -d ) xcrun xcodebuild build \ $COMMON_SETUP \ -derivedDataPath "${DERIVED_DATA_PATH}" \ -destination 'generic/platform=iOS' mkdir -p "${OUTPUT_DIR}/iphoneos" ditto "${DERIVED_DATA_PATH}/Build/Products/Release-iphoneos/CryptoSwift.framework" "${OUTPUT_DIR}/iphoneos/CryptoSwift.framework" rm -rf "${DERIVED_DATA_PATH}" # iOS Simulator DERIVED_DATA_PATH=$( mktemp -d ) xcrun xcodebuild build \ $COMMON_SETUP \ -derivedDataPath "${DERIVED_DATA_PATH}" \ -destination 'generic/platform=iOS Simulator' mkdir -p "${OUTPUT_DIR}/iphonesimulator" ditto "${DERIVED_DATA_PATH}/Build/Products/Release-iphonesimulator/CryptoSwift.framework" "${OUTPUT_DIR}/iphonesimulator/CryptoSwift.framework" rm -rf "${DERIVED_DATA_PATH}" # tvOS DERIVED_DATA_PATH=$( mktemp -d ) xcrun xcodebuild build \ $COMMON_SETUP \ -derivedDataPath "${DERIVED_DATA_PATH}" \ -destination 'generic/platform=tvOS' mkdir -p "${OUTPUT_DIR}/appletvos" ditto "${DERIVED_DATA_PATH}/Build/Products/Release-appletvos/CryptoSwift.framework" "${OUTPUT_DIR}/appletvos/CryptoSwift.framework" rm -rf "${DERIVED_DATA_PATH}" # tvOS Simulator DERIVED_DATA_PATH=$( mktemp -d ) xcrun xcodebuild build \ $COMMON_SETUP \ -derivedDataPath "${DERIVED_DATA_PATH}" \ -destination 'generic/platform=tvOS Simulator' mkdir -p "${OUTPUT_DIR}/appletvsimulator" ditto "${DERIVED_DATA_PATH}/Build/Products/Release-appletvsimulator/CryptoSwift.framework" "${OUTPUT_DIR}/appletvsimulator/CryptoSwift.framework" rm -rf "${DERIVED_DATA_PATH}" # watchOS DERIVED_DATA_PATH=$( mktemp -d ) xcrun xcodebuild build \ $COMMON_SETUP \ -derivedDataPath "${DERIVED_DATA_PATH}" \ -destination 'generic/platform=watchOS' mkdir -p "${OUTPUT_DIR}/watchos" ditto "${DERIVED_DATA_PATH}/Build/Products/Release-watchos/CryptoSwift.framework" "${OUTPUT_DIR}/watchos/CryptoSwift.framework" rm -rf "${DERIVED_DATA_PATH}" # watchOS Simulator DERIVED_DATA_PATH=$( mktemp -d ) xcrun xcodebuild build \ $COMMON_SETUP \ -derivedDataPath "${DERIVED_DATA_PATH}" \ -destination 'generic/platform=watchOS Simulator' mkdir -p "${OUTPUT_DIR}/watchsimulator" ditto "${DERIVED_DATA_PATH}/Build/Products/Release-watchsimulator/CryptoSwift.framework" "${OUTPUT_DIR}/watchsimulator/CryptoSwift.framework" rm -rf "${DERIVED_DATA_PATH}" # XCFRAMEWORK rm -rf ${SCRIPT_DIR}/../CryptoSwift.xcframework xcrun xcodebuild -quiet -create-xcframework \ -framework "${OUTPUT_DIR}/iphoneos/CryptoSwift.framework" \ -framework "${OUTPUT_DIR}/iphonesimulator/CryptoSwift.framework" \ -framework "${OUTPUT_DIR}/appletvos/CryptoSwift.framework" \ -framework "${OUTPUT_DIR}/appletvsimulator/CryptoSwift.framework" \ -framework "${OUTPUT_DIR}/watchos/CryptoSwift.framework" \ -framework "${OUTPUT_DIR}/watchsimulator/CryptoSwift.framework" \ -framework "${OUTPUT_DIR}/macos/CryptoSwift.framework" \ -framework "${OUTPUT_DIR}/maccatalyst/CryptoSwift.framework" \ -output ${SCRIPT_DIR}/../CryptoSwift.xcframework # pushd ${OUTPUT_DIR} # xcrun zip --symlinks -r -o ${BASE_PWD}/CryptoSwift.xcframework.zip CryptoSwift.xcframework # popd echo "✔️ CryptoSwift.xcframework" echo ${OUTPUT_DIR} rm -rf ${OUTPUT_DIR} cd ${BASE_PWD} ================================================ FILE: scripts/generate-contributors-list.sh ================================================ #!/bin/bash ##===----------------------------------------------------------------------===## ## ## This source file is part of the SwiftNIO open source project ## ## Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors ## Licensed under Apache License v2.0 ## ## See LICENSE.txt for license information ## See CONTRIBUTORS.txt for the list of SwiftNIO project authors ## ## SPDX-License-Identifier: Apache-2.0 ## ##===----------------------------------------------------------------------===## set -eu here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" contributors=$( cd "$here"/.. && git shortlog -es | cut -f2 | sed 's/^/- /' ) cat > "$here/../CONTRIBUTORS.txt" <<- EOF For the purpose of tracking copyright, this is the list of individuals and organizations who have contributed source code to CryptoSwift. ### Contributors $contributors **Updating this list** Please do not edit this file manually. It is generated using \`./scripts/generate-contributors-list.sh\`. If a name is misspelled or appearing multiple times: add an entry in \`./.mailmap\` EOF ================================================ FILE: scripts/swiftformat.sh ================================================ #!/bin/bash swiftformat --hexliteralcase lowercase --hexgrouping none --ranges nospace --wrapelements beforefirst --self remove $1