{"id":20186043,"url":"https://github.com/neosmart/cryptostream","last_synced_at":"2025-04-10T06:21:05.600Z","repository":{"id":57613986,"uuid":"145739625","full_name":"neosmart/cryptostream","owner":"neosmart","description":"Read and Write stream adapters for on-the-fly encryption and decryption for rust","archived":false,"fork":false,"pushed_at":"2022-08-13T20:54:31.000Z","size":51,"stargazers_count":21,"open_issues_count":1,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-04-26T18:46:16.135Z","etag":null,"topics":["crate","cryptography","cryptostreams","rust"],"latest_commit_sha":null,"homepage":"https://neosmart.net/blog/2018/transparent-encryption-and-decryption-in-rust-with-cryptostreams/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/neosmart.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}},"created_at":"2018-08-22T17:12:28.000Z","updated_at":"2023-06-16T10:02:27.000Z","dependencies_parsed_at":"2022-09-11T01:00:56.283Z","dependency_job_id":null,"html_url":"https://github.com/neosmart/cryptostream","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neosmart%2Fcryptostream","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neosmart%2Fcryptostream/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neosmart%2Fcryptostream/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neosmart%2Fcryptostream/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neosmart","download_url":"https://codeload.github.com/neosmart/cryptostream/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248166865,"owners_count":21058481,"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":["crate","cryptography","cryptostreams","rust"],"created_at":"2024-11-14T03:15:46.804Z","updated_at":"2025-04-10T06:21:05.567Z","avatar_url":"https://github.com/neosmart.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Rust Cryptostream Crate\n\n[![crates.io](https://img.shields.io/crates/v/cryptostream.svg)](https://crates.io/crates/cryptostream) [![docs.rs](https://docs.rs/cryptostream/badge.svg)](https://docs.rs/crate/cryptostream)\n\n`cryptostream` provides a rust equivalent to the [.NET\nCryptostream](https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptostream)\nclass, providing an efficient and easy solution to on-the-fly encryption or decryption of existing\n`Read` or `Write` resources. Cryptography is provided via [rust-openssl](https://github.com/sfackler/rust-openssl)\nand is fully configurable.\n\n## What is a Cryptostream?\n\nIn brief, a\n[Cryptostream](https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.cryptostream)\nis a wrapper around a stream (in rust parlance, a `Read` or `Write` type) that transparently\nencrypts or decrypts the underlying contents. After creating an instance of a `Cryptostream` with\nthe cipher, key, and IV specified, bytes written to or read from the Cryptostream are the same as\nthe `Read` or `Write` stream it is wrapping, only additionally encrypted or decrypted. It makes\nhandling encrypted sources or destinations a breeze, and requires virtually no changes to your\nexisting pipeline - it's just a `Read` or `Write`, like any other.\n\n## Crate Design\n\nAs rust (for better or for worse) lacks a `Stream` type, `cryptostream` has been implemented in both\nencryption and decryption modes twice, once as a `Read` impl and once as a `Write` impl (design cues\ntaken from the `flate2` crate), with a bonus `BufRead` impl thrown in for good measure. This means\nthat for any combination of available [ciphertext|plaintext] and desired [read|write] application,\none of the `cryptostream` impls should match your usecase. A `cryptostream` should be created\nmatching the type of resource you wish to consume (in case source data is a `Read` impl) or the type\nof resource you wish to create (in case destination is a `Write` impl).\n\nImplementations have been grouped by trait into namespace and have names conveying their\napplications:\n\n* `cryptostream::read::Encryptor`\n* `cryptostream::read::Decryptor`\n* `cryptostream::write::Encryptor`\n* `cryptostream::write::Decryptor`\n\n## `Read` vs `Write` Cryptostreams\n\nThe difference between the `Read` and `Write` variants of `cryptostream` are perhaps best\nillustrated by example. In both of the following examples, we will be decrypting ciphertext, however\nin one case we need to use `read::Decryptor` and in the other `write::Decryptor`.\n\nIn the first case, we have a `Read` source which contains the bytes we need to decrypt, and we wish\nto obtain the equivalent plaintext in memory to later perform some operation with in its decoded\nstate:\n\n```rust\n\n// This is the cipher text, base64-encoded to avoid any whitespace munging. In this\n// contrived example, we are using a binary `Vec\u003cu8\u003e` as the `Read` source containing\n// the encrypted data; in practice it could be a binary file, a network stream, or\n// anything else.\nlet src: Vec\u003cu8\u003e = decode(concat!(\n    \"vuU+0SXFWQLu8vl/o1WzmPCmf7x/O6ToGQ162Aq2CHxcnc/ax/Q8nTbRlNn0OSPrFuE3yDdO\",\n    \"VC35RmwtUIlxKIkWbnxJpRF5yRJvVByQgWX1qLW8DfMjRp7gVaFNv4qr7G65M6hbSx6hGJXv\",\n    \"Q6s1GiFwi91q0V17DI79yVrINHCXdBnUOqeLGfJ05Edu+39EQNYn4dky7VdgTP2VYZE7Vw==\",\n))\n.unwrap();\nlet key: Vec\u003c_\u003e = decode(\"kjtbxCPw3XPFThb3mKmzfg==\").unwrap();\nlet iv: Vec\u003c_\u003e = decode(\"dB0Ej+7zWZWTS5JUCldWMg==\").unwrap();\n\n// The source can be anything implementing `Read`. In this case, a simple \u0026[u8] slice.\nlet mut decryptor =\n    read::Decryptor::new(src.as_slice(), Cipher::aes_128_cbc(), \u0026key, \u0026iv).unwrap();\n\nlet mut decrypted = [0u8; 1024]; // a buffer to decrypt into\nlet mut bytes_decrypted = 0;\n\nloop {\n    // Just read from the `Decryptor` as if it were any other `Read` impl,\n    // the decryption takes place automatically.\n    let read_count = decryptor.read(\u0026mut decrypted[bytes_decrypted..]).unwrap();\n    bytes_decrypted += read_count;\n    if read_count == 0 {\n        break;\n    }\n}\n\nprintln!(\"{}\", String::from_utf8_lossy(\u0026decrypted));\n\n```\n\nNow what about if you want to _write out_ the decrypted contents instead of _read_ them, but still\nwish to perform decryption all the same?\n\n```rust\n\n// Starting again with the same encrypted bytestream, encoded as base64:\nlet src: Vec\u003cu8\u003e = decode(concat!(\n    \"vuU+0SXFWQLu8vl/o1WzmPCmf7x/O6ToGQ162Aq2CHxcnc/ax/Q8nTbRlNn0OSPrFuE3yDdO\",\n    \"VC35RmwtUIlxKIkWbnxJpRF5yRJvVByQgWX1qLW8DfMjRp7gVaFNv4qr7G65M6hbSx6hGJXv\",\n    \"Q6s1GiFwi91q0V17DI79yVrINHCXdBnUOqeLGfJ05Edu+39EQNYn4dky7VdgTP2VYZE7Vw==\"\n))\n.unwrap();\nlet key: Vec\u003c_\u003e = decode(\"kjtbxCPw3XPFThb3mKmzfg==\").unwrap();\nlet iv: Vec\u003c_\u003e = decode(\"dB0Ej+7zWZWTS5JUCldWMg==\").unwrap();\n\n// The destination can be any object implementing `Write`: in this case, a `Vec\u003cu8\u003e`.\nlet mut decrypted = Vec::new();\n\n// When a `cryptostream` is dropped, all buffers are flushed and it is automatically\n// finalized. We can either call `drop()` on the cryptostream or put its usage in a\n// separate scope.\n{\n    let mut decryptor =\n        write::Decryptor::new(\u0026mut decrypted, Cipher::aes_128_cbc(), \u0026key, \u0026iv).unwrap();\n\n    let mut bytes_decrypted = 0;\n\n    while bytes_decrypted != src.len() {\n        // Just write encrypted ciphertext to the `Decryptor` instance as if it were any\n        // other `Write` impl. Decryption takes place automatically.\n        let write_count = decryptor.write(\u0026src[bytes_decrypted..]).unwrap();\n        bytes_decrypted += write_count;\n    }\n}\n\n// The underlying `Write` instance is only guaranteed to contain the complete and\n// finalized contents after the cryptostream is either explicitly finalized with a\n// call to `Cryptostream::finish()` or when it's dropped (either at the end of a scope\n// or via an explicit call to `drop()`, whichever you prefer).\nprintln!(\"{}\", String::from_utf8_lossy(\u0026decrypted));\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneosmart%2Fcryptostream","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneosmart%2Fcryptostream","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneosmart%2Fcryptostream/lists"}