{"id":1952,"url":"https://github.com/jedisct1/swift-sodium","last_synced_at":"2026-04-09T18:39:57.733Z","repository":{"id":25125097,"uuid":"28546877","full_name":"jedisct1/swift-sodium","owner":"jedisct1","description":"Safe and easy to use crypto for iOS and macOS","archived":false,"fork":false,"pushed_at":"2024-12-31T13:50:53.000Z","size":67053,"stargazers_count":531,"open_issues_count":3,"forks_count":191,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-05-14T18:02:13.182Z","etag":null,"topics":["cryptography","libsodium","swift"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jedisct1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-12-27T21:34:25.000Z","updated_at":"2025-05-09T18:46:28.000Z","dependencies_parsed_at":"2024-06-18T12:24:13.996Z","dependency_job_id":"e4f5a473-7ee8-4ee2-b00c-e8106725ffcc","html_url":"https://github.com/jedisct1/swift-sodium","commit_stats":{"total_commits":481,"total_committers":46,"mean_commits":"10.456521739130435","dds":0.4428274428274428,"last_synced_commit":"25d663c0e550dd8258c3508821a0b1b132e83721"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jedisct1%2Fswift-sodium","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jedisct1%2Fswift-sodium/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jedisct1%2Fswift-sodium/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jedisct1%2Fswift-sodium/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jedisct1","download_url":"https://codeload.github.com/jedisct1/swift-sodium/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254198453,"owners_count":22030964,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cryptography","libsodium","swift"],"created_at":"2024-01-05T20:15:59.765Z","updated_at":"2026-04-09T18:39:57.697Z","avatar_url":"https://github.com/jedisct1.png","language":"C","funding_links":[],"categories":["Security","Libs","\u003ca id=\"58cd9084afafd3cd293564c1d615dd7f\"\u003e\u003c/a\u003e工具","C","Frameworks and Libs","Security [🔝](#readme)"],"sub_categories":["Encryption","Security","\u003ca id=\"d0108e91e6863289f89084ff09df39d0\"\u003e\u003c/a\u003e新添加的","Swift","Other free courses"],"readme":"# Swift-Sodium\n\nSwift-Sodium provides a safe and easy to use interface to perform common cryptographic operations on macOS, iOS, tvOS and watchOS.\n\nIt leverages the [Sodium](https://download.libsodium.org/doc/) library, and although Swift is the primary target, the framework can also be used in Objective-C applications.\n\n## Please help!\n\nThe current Swift-Sodium documentation is not great. Your help to improve it and make it awesome would be very appreciated!\n\n## Usage\n\nTo add Swift-Sodium as dependency to your Xcode project, select `File` \u003e `Swift Packages` \u003e `Add Package Dependency`, enter its repository URL: `https://github.com/jedisct1/swift-sodium.git` and import `Sodium` as well as `Clibsodium`.\n\nThen, to use it in your source code, add:\n\n```swift\nimport Sodium\n```\n\nThe Sodium library itself doesn't have to be installed on the system: the repository already includes a precompiled library for armv7, armv7s, arm64, as well as for the iOS simulator, WatchOS and Catalyst.\n\nThe `Clibsodium.xcframework` framework has been generated by the\n[dist-build/apple-xcframework.sh](https://github.com/jedisct1/libsodium/blob/master/dist-build/apple-xcframework.sh)\nscript.\n\nRunning this script on Xcode 16.2 on the revision `131c6e771c671867fabcec3bdf8c45c4c38a131b` of libsodium generates files identical to the ones present in this repository.\n\n## Secret-key cryptography\n\nMessages are encrypted and decrypted using the same secret key, this is also known as symmetric cryptography.\n\nA key can be generated using the `key()` method, derived from a password using the Password Hashing API, or computed using a secret key and the peer's public key utilising the Key Exchange API.\n\n### Authenticated encryption for a sequence of messages\n\n```swift\nlet sodium = Sodium()\nlet message1 = \"Message 1\".bytes\nlet message2 = \"Message 2\".bytes\nlet message3 = \"Message 3\".bytes\n\nlet secretkey = sodium.secretStream.xchacha20poly1305.key()\n\n/* stream encryption */\n\nlet stream_enc = sodium.secretStream.xchacha20poly1305.initPush(secretKey: secretkey)!\nlet header = stream_enc.header()\nlet encrypted1 = stream_enc.push(message: message1)!\nlet encrypted2 = stream_enc.push(message: message2)!\nlet encrypted3 = stream_enc.push(message: message3, tag: .FINAL)!\n\n/* stream decryption */\n\nlet stream_dec = sodium.secretStream.xchacha20poly1305.initPull(secretKey: secretkey, header: header)!\nlet (message1_dec, tag1) = stream_dec.pull(cipherText: encrypted1)!\nlet (message2_dec, tag2) = stream_dec.pull(cipherText: encrypted2)!\nlet (message3_dec, tag3) = stream_dec.pull(cipherText: encrypted3)!\n```\n\nA stream is a sequence of messages, that will be encrypted as they depart, and, decrypted as they arrive. The encrypted messages are expected to be received in the same order as they were sent.\n\nStreams can be arbitrarily long. This API can thus be used for file encryption, by splitting files into small chunks, so that the whole file doesn't need to reside in memory concurrently.\n\nIt can also be used to exchange a sequence of messages between two peers.\n\nThe decryption function automatically checks that chunks have been received without modification, and truncation or reordering.\n\nA tag is attached to each message, and can be used to signal the end of a sub-sequence (`PUSH`), or the end of the string (`FINAL`).\n\n### Authenticated encryption for single messages\n\n```swift\nlet sodium = Sodium()\nlet message = \"My Test Message\".bytes\nlet secretKey = sodium.secretBox.key()\nlet encrypted: Bytes = sodium.secretBox.seal(message: message, secretKey: secretKey)!\nif let decrypted = sodium.secretBox.open(nonceAndAuthenticatedCipherText: encrypted, secretKey: secretKey) {\n    // authenticator is valid, decrypted contains the original message\n}\n```\n\nThis API encrypts a message. The decryption process will check that the messages haven't been tampered with before decrypting them.\n\nMessages encrypted this way are independent: if multiple messages are sent this way, the recipient cannot detect if some messages have been duplicated, deleted or reordered without the sender including additional data with each message.\n\nOptionally, `SecretBox` provides the ability to utilize a user-defined nonce via `seal(message: secretKey: nonce:)`.\n\n## Public-key Cryptography\n\nWith public-key cryptography, each peer has two keys: a secret (private) key, that has to remain secret, and a public key that anyone can use to send an encrypted message to that peer. That public key can be only be used to encrypt a message. The corresponding secret is required to decrypt it.\n\n### Authenticated Encryption\n\n```swift\nlet sodium = Sodium()\nlet aliceKeyPair = sodium.box.keyPair()!\nlet bobKeyPair = sodium.box.keyPair()!\nlet message = \"My Test Message\".bytes\n\nlet encryptedMessageFromAliceToBob: Bytes =\n    sodium.box.seal(message: message,\n                    recipientPublicKey: bobKeyPair.publicKey,\n                    senderSecretKey: aliceKeyPair.secretKey)!\n\nlet messageVerifiedAndDecryptedByBob =\n    sodium.box.open(nonceAndAuthenticatedCipherText: encryptedMessageFromAliceToBob,\n                    senderPublicKey: aliceKeyPair.publicKey,\n                    recipientSecretKey: bobKeyPair.secretKey)\n```\n\nThis operation encrypts and sends a message to someone using their public key.\n\nThe recipient has to know the sender's public key as well, and will reject a message that doesn't appear to be valid for the expected public key.\n\n`seal()` automatically generates a nonce and prepends it to the ciphertext. `open()` extracts the nonce and decrypts the ciphertext.\n\nOptionally, `Box` provides the ability to utilize a user-defined nonce via `seal(message: recipientPublicKey: senderSecretKey: nonce:)`.\n\nThe `Box` class also provides alternative functions and parameters to deterministically generate key pairs, to retrieve the nonce and/or the authenticator, and to detach them from the original message.\n\n## Anonymous Encryption (Sealed Boxes)\n\n```swift\nlet sodium = Sodium()\nlet bobKeyPair = sodium.box.keyPair()!\nlet message = \"My Test Message\".bytes\n\nlet encryptedMessageToBob =\n    sodium.box.seal(message: message, recipientPublicKey: bobKeyPair.publicKey)!\n\nlet messageDecryptedByBob =\n    sodium.box.open(anonymousCipherText: encryptedMessageToBob,\n                    recipientPublicKey: bobKeyPair.publicKey,\n                    recipientSecretKey: bobKeyPair.secretKey)\n```\n\n`seal()` generates an ephemeral keypair, uses the ephemeral secret key in the encryption process, combines the ephemeral public key with the ciphertext, then destroys the keypair.\n\nThe sender cannot decrypt the resulting ciphertext. `open()` extracts the public key and decrypts using the recipient's secret key. Message integrity is verified, but the sender's identity cannot be correlated to the ciphertext.\n\n## Key exchange\n\n```swift\nlet sodium = Sodium()\nlet aliceKeyPair = sodium.keyExchange.keyPair()!\nlet bobKeyPair = sodium.keyExchange.keyPair()!\n\nlet sessionKeyPairForAlice = sodium.keyExchange.sessionKeyPair(publicKey: aliceKeyPair.publicKey,\n    secretKey: aliceKeyPair.secretKey, otherPublicKey: bobKeyPair.publicKey, side: .CLIENT)!\nlet sessionKeyPairForBob = sodium.keyExchange.sessionKeyPair(publicKey: bobKeyPair.publicKey,\n    secretKey: bobKeyPair.secretKey, otherPublicKey: aliceKeyPair.publicKey, side: .SERVER)!\n\nlet aliceToBobKeyEquality = sodium.utils.equals(sessionKeyPairForAlice.tx, sessionKeyPairForBob.rx) // true\nlet bobToAliceKeyEquality = sodium.utils.equals(sessionKeyPairForAlice.rx, sessionKeyPairForBob.tx) // true\n```\n\n## Public-key signatures\n\nSignatures allow multiple parties to verify the authenticity of a public message, using the public key of the author's message.\n\nThis can be especially useful to sign software updates.\n\n### Detached signatures\n\nThe signature is generated separately to the original message.\n\n```swift\nlet sodium = Sodium()\nlet message = \"My Test Message\".bytes\nlet keyPair = sodium.sign.keyPair()!\nlet signature = sodium.sign.signature(message: message, secretKey: keyPair.secretKey)!\nif sodium.sign.verify(message: message,\n                      publicKey: keyPair.publicKey,\n                      signature: signature) {\n    // signature is valid\n}\n```\n\n### Attached signatures\n\nThe signature is generated and prepended to the original message.\n\n```swift\nlet sodium = Sodium()\nlet message = \"My Test Message\".bytes\nlet keyPair = sodium.sign.keyPair()!\nlet signedMessage = sodium.sign.sign(message: message, secretKey: keyPair.secretKey)!\nif let unsignedMessage = sodium.sign.open(signedMessage: signedMessage, publicKey: keyPair.publicKey) {\n    // signature is valid\n}\n```\n\n## Hashing\n\n### Deterministic hashing\n\nHashing effectively \"fingerprints\" input data, no matter what its size, and returns a fixed length \"digest\".\n\nThe digest length can be configured as required, from 16 to 64 bytes.\n\n```swift\nlet sodium = Sodium()\nlet message = \"My Test Message\".bytes\nlet hash = sodium.genericHash.hash(message: message)\nlet hashOfSize32Bytes = sodium.genericHash.hash(message: message, outputLength: 32)\n```\n\n### Keyed hashing\n\n```swift\nlet sodium = Sodium()\nlet message = \"My Test Message\".bytes\nlet key = \"Secret key\".bytes\nlet h = sodium.genericHash.hash(message: message, key: key)\n```\n\n### Streaming\n\n```swift\nlet sodium = Sodium()\nlet message1 = \"My Test \".bytes\nlet message2 = \"Message\".bytes\nlet key = \"Secret key\".bytes\nlet stream = sodium.genericHash.initStream(key: key)!\nstream.update(input: message1)\nstream.update(input: message2)\nlet h = stream.final()\n```\n\n### Short-output hashing (SipHash)\n\n```swift\nlet sodium = Sodium()\nlet message = \"My Test Message\".bytes\nlet key = sodium.randomBytes.buf(length: sodium.shortHash.KeyBytes)!\nlet h = sodium.shortHash.hash(message: message, key: key)\n```\n\n## Random numbers generation\n\nRandom number generation produces cryptographically secure pseudorandom numbers suitable as key material.\n\n```swift\nlet sodium = Sodium()\nlet randomBytes = sodium.randomBytes.buf(length: 1000)!\nlet seed = \"0123456789abcdef0123456789abcdef\".bytes\nlet stream = sodium.randomBytes.deterministic(length: 1000, seed: seed)!\n```\n\nUse `RandomBytes.Generator` as a generator to produce cryptographically secure pseudorandom numbers.\n\n```swift\nvar rng = RandomBytes.Generator()\nlet randomUInt32 = UInt32.random(in: 0...10, using: \u0026rng)\nlet randomUInt64 = UInt64.random(in: 0...10, using: \u0026rng)\nlet randomInt = Int.random(in: 0...10, using: \u0026rng)\nlet randomDouble = Double.random(in: 0...1, using: \u0026rng)\n```\n\n## Password hashing\n\nPassword hashing provides the ability to derive key material from a low-entropy password. Password hashing functions are designed to be expensive to hamper brute force attacks, thus the computational and memory parameters may be user-defined.\n\n```swift\nlet sodium = Sodium()\nlet password = \"Correct Horse Battery Staple\".bytes\nlet hashedStr = sodium.pwHash.str(passwd: password,\n                                  opsLimit: sodium.pwHash.OpsLimitInteractive,\n                                  memLimit: sodium.pwHash.MemLimitInteractive)!\n\nif sodium.pwHash.strVerify(hash: hashedStr, passwd: password) {\n    // Password matches the given hash string\n} else {\n    // Password doesn't match the given hash string\n}\n\nif sodium.pwHash.strNeedsRehash(hash: hashedStr,\n                                opsLimit: sodium.pwHash.OpsLimitInteractive,\n                                memLimit: sodium.pwHash.MemLimitInteractive) {\n    // Previously hashed password should be recomputed because the way it was\n    // hashed doesn't match the current algorithm and the given parameters.\n}\n```\n\n## Authentication tags\n\nThe `sodium.auth.tag()` function computes an authentication tag (HMAC) using a message and a key. Parties knowing the key can then verify the authenticity of the message using the same parameters and the `sodium.auth.verify()` function.\n\nAuthentication tags are not signatures: the same key is used both for computing and verifying a tag. Therefore, verifiers can also compute tags for arbitrary messages.\n\n```swift\nlet sodium = Sodium()\nlet input = \"test\".bytes\nlet key = sodium.auth.key()\nlet tag = sodium.auth.tag(message: input, secretKey: key)!\nlet tagIsValid = sodium.auth.verify(message: input, secretKey: key, tag: tag)\n```\n\n## Key derivation\n\nThe `sodium.keyDerivation.derive()` function generates a subkey using an input (master) key, an index, and a 8 bytes string identifying the context. Up to (2^64) - 1 subkeys can be generated for each context, by incrementing the index.\n\n```swift\nlet sodium = Sodium()\nlet secretKey = sodium.keyDerivation.keygen()!\n\nlet subKey1 = sodium.keyDerivation.derive(secretKey: secretKey,\n                                          index: 0, length: 32,\n                                          context: \"Context!\")\nlet subKey2 = sodium.keyDerivation.derive(secretKey: secretKey,\n                                          index: 1, length: 32,\n                                          context: \"Context!\")\n```\n\n## Utilities\n\n### Zeroing memory\n\n```swift\nlet sodium = Sodium()\nvar dataToZero = \"Message\".bytes\nsodium.utils.zero(\u0026dataToZero)\n```\n\n### Constant-time comparison\n\n```swift\nlet sodium = Sodium()\nlet secret1 = \"Secret key\".bytes\nlet secret2 = \"Secret key\".bytes\nlet equality = sodium.utils.equals(secret1, secret2)\n```\n\n### Padding\n\n```swift\nlet sodium = Sodium()\nvar bytes = \"test\".bytes\n\n// make bytes.count a multiple of 16\nsodium.utils.pad(bytes: \u0026bytes, blockSize: 16)!\n\n// restore original size\nsodium.utils.unpad(bytes: \u0026bytes, blockSize: 16)!\n```\n\nPadding can be useful to hide the length of a message before it is encrypted.\n\n### Constant-time hexadecimal encoding\n\n```swift\nlet sodium = Sodium()\nlet bytes = \"Secret key\".bytes\nlet hex = sodium.utils.bin2hex(bytes)\n```\n\n### Hexadecimal decoding\n\n```swift\nlet sodium = Sodium()\nlet data1 = sodium.utils.hex2bin(\"deadbeef\")\nlet data2 = sodium.utils.hex2bin(\"de:ad be:ef\", ignore: \" :\")\n```\n\n### Constant-time base64 encoding\n\n```swift\nlet sodium = Sodium()\nlet b64 = sodium.utils.bin2base64(\"data\".bytes)!\nlet b64_2 = sodium.utils.bin2base64(\"data\".bytes, variant: .URLSAFE_NO_PADDING)!\n```\n\n### Base64 decoding\n\n```swift\nlet data1 = sodium.utils.base642bin(b64)\nlet data2 = sodium.utils.base642bin(b64, ignore: \" \\n\")\nlet data3 = sodium.utils.base642bin(b64_2, variant: .URLSAFE_NO_PADDING, ignore: \" \\n\")\n```\n\n## Helpers to build custom constructions\n\nOnly use the functions below if you know that you absolutely need them, and know how to use them correctly.\n\n## Unauthenticated encryption\n\nThe `sodium.stream.xor()` function combines (using the XOR operation) an arbitrary-long input with the output of a deterministic key stream derived from a key and a nonce. The same operation applied twice produces the original input.\n\nNo authentication tag is added to the output. The data can be tampered with; an adversary can flip arbitrary bits.\n\nIn order to encrypt data using a secret key, the `SecretBox` class is likely to be what you are looking for.\n\nIn order to generate a deterministic stream out of a seed, the `RandomBytes.deterministic_rand()` function is likely to be what you need.\n\n```swift\nlet sodium = Sodium()\nlet input = \"test\".bytes\nlet key = sodium.stream.key()\nlet (output, nonce) = sodium.stream.xor(input: input, secretKey: key)!\nlet twice = sodium.stream.xor(input: output, nonce: nonce, secretKey: key)!\n\nXCTAssertEqual(input, twice)\n```\n\n## Algorithms\n\n* Stream ciphers: XChaCha20, XSalsa20\n* AEADs: XChaCha20Poly1305, AEGIS-128L, AEGIS-256, AES256-GCM\n* MACs: Poly1305, HMAC-SHA512/256\n* Hash function: BLAKE2B\n* Key exchange: X25519\n* Signatures: Ed25519\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjedisct1%2Fswift-sodium","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjedisct1%2Fswift-sodium","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjedisct1%2Fswift-sodium/lists"}