{"id":13399242,"url":"https://github.com/jedisct1/libsodium-php","last_synced_at":"2025-05-15T10:06:03.169Z","repository":{"id":11776317,"uuid":"14314693","full_name":"jedisct1/libsodium-php","owner":"jedisct1","description":"The PHP extension for libsodium.","archived":false,"fork":false,"pushed_at":"2024-12-31T13:59:17.000Z","size":703,"stargazers_count":556,"open_issues_count":3,"forks_count":77,"subscribers_count":25,"default_branch":"master","last_synced_at":"2025-04-14T16:56:13.678Z","etag":null,"topics":["crypto","cryptography","halite","libsodium","libsodium-php","php","php-extension","security"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","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":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-11-11T22:00:34.000Z","updated_at":"2025-01-09T06:20:30.000Z","dependencies_parsed_at":"2024-01-16T09:57:07.709Z","dependency_job_id":"7731518c-a380-44fa-b75e-103aa64df18d","html_url":"https://github.com/jedisct1/libsodium-php","commit_stats":null,"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jedisct1%2Flibsodium-php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jedisct1%2Flibsodium-php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jedisct1%2Flibsodium-php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jedisct1%2Flibsodium-php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jedisct1","download_url":"https://codeload.github.com/jedisct1/libsodium-php/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254319718,"owners_count":22051072,"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":["crypto","cryptography","halite","libsodium","libsodium-php","php","php-extension","security"],"created_at":"2024-07-30T19:00:35.602Z","updated_at":"2025-05-15T10:05:58.135Z","avatar_url":"https://github.com/jedisct1.png","language":"C","funding_links":[],"categories":["C","TODO scan for Android support in followings","字符串处理"],"sub_categories":[],"readme":"libsodium-php\n=============\n\nA simple, low-level PHP extension for [libsodium](https://github.com/jedisct1/libsodium).\n\nRequires libsodium \u003e= 1.0.9 and PHP 7.{0,1,2,3,4}.x or PHP 8.0.x\n\nFull documentation here:\n[Using Libsodium in PHP Projects](https://paragonie.com/book/pecl-libsodium),\na guide to using the libsodium PHP extension for modern, secure, and\nfast cryptography.\n\nInstallation\n============\n\nlibsodium (and, if you are using binary packages, on some\ndistributions, `libsodium-dev` as well) has to be installed before\nthis extension.\n\nThen, use the PHP extension manager:\n\n```sh\n$ sudo pecl install -f libsodium\n```\n\nOn some Linux distributions such as Debian, you may have to install\nPECL (`php-pear`), the PHP development package (`php-dev`) and a compiler\n(`build-essential`) prior to running this command.\n\nlibsodium-php 1.x compatibility API for libsodium-php 2.x\n==========================================================\n\nFor projects using the 1.x API, or willing to use it, a compatibility\nlayer is available.\n\n[Polyfill Libsodium](https://github.com/mollie/polyfill-libsodium)\nbrings the `\\Sodium\\` namespace back.\n\nExamples\n========\n\n## Encrypt a single message using a secret key\n\nEncryption:\n\n```php\n$secretKey = sodium_crypto_secretbox_keygen();\n$message = 'Sensitive information';\n\n$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);\n$encryptedMessage = sodium_crypto_secretbox($message, $nonce, $secretKey);\n```\n\nDecryption:\n\n```php\n$decryptedMessage = sodium_crypto_secretbox_open($encryptedMessage, $nonce, $secretKey);\n```\n\nHow it works:\n\n`$secret_key` is a secret key. Not a password. It's binary data, not\nsomething designed to be human readable, but rather to have a key\nspace as large as possible for a given length.\nThe `keygen()` function creates such a key. That has to remain secret,\nas it is used both to encrypt and decrypt data.\n\n`$nonce` is a unique value. Like the secret, its length is fixed. But\nit doesn't have to be secret, and can be sent along with the encrypted\nmessage. The nonce doesn't have to be unpredictable either. It just has\nto be unique for a given key. With the `secretbox()` API, using\n`random_bytes()` is a totally fine way to generate nonces.\n\nEncrypted messages are slightly larger than unencrypted messages,\nbecause they include an authenticator, used by the decryption function\nto check that the content was not altered.\n\n## Encrypt a single message using a secret key, and hide its length\n\nEncryption:\n\n```php\n$secretKey = sodium_crypto_secretbox_keygen();\n$message = 'Sensitive information';\n$blockSize = 16;\n\n$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);\n$paddedMessage = sodium_pad($message, $blockSize);\n$encryptedMessage = sodium_crypto_secretbox($paddedMessage, $nonce, $secretKey);\n```\n\nDecryption:\n\n```php\n$decryptedPaddedMessage = sodium_crypto_secretbox_open($encryptedMessage, $nonce, $secretKey);\n$decryptedMessage = sodium_unpad($decryptedPaddedMessage, $blockSize);\n```\n\nHow it works:\n\nSometimes, the length of a message may provide a lot of information\nabout its nature. If a message is one of \"yes\", \"no\" and \"maybe\",\nencrypting the message doesn't help: knowing the length is enough to\nknow what the message is.\n\nPadding is a technique to mitigate this, by making the length a\nmultiple of a given block size.\n\nMessages must be padded prior to encryption, and unpadded after\ndecryption.\n\n## Encrypt a file using a secret key\n\n```php\n$secretKey = sodium_crypto_secretstream_xchacha20poly1305_keygen();\n$inputFile = '/tmp/example.original';\n$encryptedFile = '/tmp/example.enc';\n$chunkSize = 4096;\n\n$fdIn = fopen($inputFile, 'rb');\n$fdOut = fopen($encryptedFile, 'wb');\n\n[$stream, $header] = sodium_crypto_secretstream_xchacha20poly1305_init_push($secretKey);\n\nfwrite($fdOut, $header);\n\n$tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE;\ndo {\n    $chunk = fread($fdIn, $chunkSize);\n\n    if (feof($fdIn)) {\n        $tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL;\n    }\n\n    $encryptedChunk = sodium_crypto_secretstream_xchacha20poly1305_push($stream, $chunk, '', $tag);\n    fwrite($fdOut, $encryptedChunk);\n} while ($tag !== SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL);\n\nfclose($fdOut);\nfclose($fdIn);\n```\n\nDecrypt the file:\n\n```php\n$decryptedFile = '/tmp/example.dec';\n\n$fdIn = fopen($encryptedFile, 'rb');\n$fdOut = fopen($decryptedFile, 'wb');\n\n$header = fread($fdIn, SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES);\n\n$stream = sodium_crypto_secretstream_xchacha20poly1305_init_pull($header, $secretKey);\ndo {\n    $chunk = fread($fdIn, $chunkSize + SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES);\n    [$decryptedChunk, $tag] = sodium_crypto_secretstream_xchacha20poly1305_pull($stream, $chunk);\n\n    fwrite($fdOut, $decryptedChunk);\n} while (!feof($fdIn) \u0026\u0026 $tag !== SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL);\n$ok = feof($fdIn);\n\nfclose($fdOut);\nfclose($fdIn);\n\nif (!$ok) {\n    die('Invalid/corrupted input');\n}\n```\n\nHow it works:\n\nThere's a little bit more code than in the previous examples.\n\nIn fact, `crypto_secretbox()` would work to encrypt as file, but only\nif that file is pretty small. Since we have to provide the entire\ncontent as a string, it has to fit in memory.\n\nIf the file is large, we can split it into small chunks, and encrypt\nchunks individually.\n\nBy doing so, we can encrypt arbitrary large files. But we need to make\nsure that chunks cannot be deleted, truncated, duplicated and\nreordered. In other words, we don't have a single \"message\", but a\nstream of messages, and during the decryption process, we need a way\nto check that the whole stream matches what we encrypted.\n\nSo we create a new stream (`init_push`) and push a sequence of messages\ninto it (`push`). Each individual message has a tag attached to it, by\ndefault `TAG_MESSAGE`. In order for the decryption process to know\nwhere the end of the stream is, we tag the last message with the\n`TAG_FINAL` tag.\n\nWhen we consume the stream (`init_pull`, then `pull` for each\nmessage), we check that they can be properly decrypted, and retrieve\nboth the decrypted chunks and the attached tags. If we read the last\nchunk (`TAG_FINAL`) and we are at the end of the file, we know that we\ncompletely recovered the original stream.\n\n## Encrypt a file using a key derived from a password:\n\n```php\n$password = 'password';\n$inputFile = '/tmp/example.original';\n$encryptedFile = '/tmp/example.enc';\n$chunkSize = 4096;\n\n$alg = SODIUM_CRYPTO_PWHASH_ALG_DEFAULT;\n$opsLimit = SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE;\n$memLimit = SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE;\n$salt = random_bytes(SODIUM_CRYPTO_PWHASH_SALTBYTES);\n\n$secretKey = sodium_crypto_pwhash(\n    SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES,\n    $password,\n    $salt,\n    $opsLimit,\n    $memLimit,\n    $alg\n);\n\n$fdIn = fopen($inputFile, 'rb');\n$fdOut = fopen($encryptedFile, 'wb');\n\nfwrite($fdOut, pack('C', $alg));\nfwrite($fdOut, pack('P', $opsLimit));\nfwrite($fdOut, pack('P', $memLimit));\nfwrite($fdOut, $salt);\n\n[$stream, $header] = sodium_crypto_secretstream_xchacha20poly1305_init_push($secretKey);\n\nfwrite($fdOut, $header);\n\n$tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE;\ndo {\n    $chunk = fread($fdIn, $chunkSize);\n    if (feof($fdIn)) {\n        $tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL;\n    }\n\n    $encryptedChunk = sodium_crypto_secretstream_xchacha20poly1305_push($stream, $chunk, '', $tag);\n    fwrite($fdOut, $encryptedChunk);\n} while ($tag !== SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL);\n\nfclose($fdOut);\nfclose($fdIn);\n```\n\nRead the stored parameters and decrypt the file:\n\n```php\n$decryptedFile = '/tmp/example.dec';\n\n$fdIn = fopen($encryptedFile, 'rb');\n$fdOut = fopen($decryptedFile, 'wb');\n\n$alg = unpack('C', fread($fdIn, 1))[1];\n$opsLimit = unpack('P', fread($fdIn, 8))[1];\n$memLimit = unpack('P', fread($fdIn, 8))[1];\n$salt = fread($fdIn, SODIUM_CRYPTO_PWHASH_SALTBYTES);\n\n$header = fread($fdIn, SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES);\n\n$secretKey = sodium_crypto_pwhash(\n    SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES,\n    $password,\n    $salt,\n    $opsLimit,\n    $memLimit,\n    $alg\n);\n\n$stream = sodium_crypto_secretstream_xchacha20poly1305_init_pull($header, $secretKey);\ndo {\n    $chunk = fread($fdIn, $chunkSize + SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES);\n    $res = sodium_crypto_secretstream_xchacha20poly1305_pull($stream, $chunk);\n\n    if ($res === false) {\n        break;\n    }\n    \n    [$decrypted_chunk, $tag] = $res;\n    fwrite($fdOut, $decrypted_chunk);\n} while (!feof($fdIn) \u0026\u0026 $tag !== SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL);\n$ok = feof($fdIn);\n\nfclose($fdOut);\nfclose($fdIn);\n\nif (!$ok) {\n    die('Invalid/corrupted input');\n}\n```\n\nHow it works:\n\nA password cannot be directly used as a secret key. Passwords are\nshort, must be typable on a keyboard, and people who don't use a\npassword manager should be able to remember them.\n\nA 8 characters password is thus way weaker than a 8 bytes key.\n\nThe `sodium_crypto_pwhash()` function perform a computationally\nintensive operation on a password in order to derive a secret key.\n\nBy doing so, brute-forcing all possible passwords in order to find the\nsecret key used to encrypt the data becomes an expensive operation.\n\nMultiple algorithms can be used to derive a key from a password, and\nfor each of them, different parameters can be chosen. It is important\nto store all of these along with encrypted data. Using the same\nalgorithm and the same parameters, the same secret key can be\ndeterministically recomputed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjedisct1%2Flibsodium-php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjedisct1%2Flibsodium-php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjedisct1%2Flibsodium-php/lists"}