{"id":27612780,"url":"https://github.com/lauslim12/vigenere","last_synced_at":"2025-04-23T01:55:37.307Z","repository":{"id":40412805,"uuid":"487896805","full_name":"lauslim12/vigenere","owner":"lauslim12","description":"Dependency-free, secure symmetric encryption implementation with Vigenère-Vernam Cipher algorithm as a library for Go. Acts as a One-Time Pad (OTP) to ensure maximum security, and supports custom alphabets.","archived":false,"fork":false,"pushed_at":"2022-05-10T09:25:07.000Z","size":25,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-23T01:55:34.232Z","etag":null,"topics":["algorithms","encryption","encryption-decryption","go","library","one-time-pad","security","vigenere","vigenere-cipher"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/lauslim12/vigenere","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lauslim12.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-05-02T15:30:56.000Z","updated_at":"2023-10-12T12:55:40.000Z","dependencies_parsed_at":"2022-08-09T19:40:36.275Z","dependency_job_id":null,"html_url":"https://github.com/lauslim12/vigenere","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/lauslim12%2Fvigenere","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lauslim12%2Fvigenere/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lauslim12%2Fvigenere/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lauslim12%2Fvigenere/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lauslim12","download_url":"https://codeload.github.com/lauslim12/vigenere/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250354301,"owners_count":21416751,"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":["algorithms","encryption","encryption-decryption","go","library","one-time-pad","security","vigenere","vigenere-cipher"],"created_at":"2025-04-23T01:55:36.626Z","updated_at":"2025-04-23T01:55:37.293Z","avatar_url":"https://github.com/lauslim12.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Vigenère\n\nProvides a dependency-free, secure symmetric encryption implementation with Vigenère-Vernam Cipher algorithm as a library for Go. Acts as a One-Time Pad (OTP) to ensure maximum security, and supports custom alphabets.\n\n## About\n\nVigenère-Vernam Cipher algorithm is theoretically a 100% secure encryption algorithm, as long as you follow these (impossible) three points:\n\n- The key must be as long as the plaintext.\n- The key must be generated with true random number generator (TRNG).\n- The key must be secret and never reused.\n\nIn Computer Security, there are three pillars: Confidentiality (ensures only authorized personnel will read the data), Integrity (ensures data\nis not tampered), and Availability (ensures the data can be accessed anytime). Confidentiality is assured with this cipher, but the\nintegrity and availability are not 100% covered. Because of this, technically, One-Time Pads are usually not feasible to implement in the\ncurrent era. Several reasons will answer why:\n\n- Storage: Storing a long pad with an equivalent length secret requires memory. Imagine if there are 5 million people, how much will the memory cost be?\n- True randomness: Computers are deterministic, and they have no idea on how to create random numbers (unlike humans).\n- Authentication: One-Time Pads are stream ciphers and do not provide Message Authentication Codes (MAC). A malicious party can bit-flip the ciphertext.\n- Transport: One-Time Pads are as secure as the secure channel used to deliver the keys. Internet is not secure enough.\n\nTrying to implement One-Time Pads in the modern era raises a single question:\n\n- If you can create a completely secure channel that is unable to be hacked by people, why don't you use that channel instead?\n\n## Algorithm\n\nThe algorithm for encryption:\n\n- Define a character set / alphabets to be used and a plaintext to be encrypted. In this case, let's assume that our character set is A to Z, with A is represented by 0, B is represented by 1, C is represented by 2, and so on and so forth.\n- Generate a set of random numbers whose length is as long as the plaintext.\n- Transform the plaintext into a numerical representative of your character set. For example, `ABC` with above character set is represented as `012`.\n- Sum the plaintext numerical representative and the random numbers.\n- Modulo the result by the length of your character set.\n- Transform the result to the numerical representative. This is your ciphertext.\n\nThe algorithm for decryption:\n\n- Transform the ciphertext and the secret in the numerical representative form.\n- Subtract the ciphertext with the secret. If any letter goes below zero, add the length of your character set.\n- Transform the result as the numerical representative. This is your plaintext.\n\nTo showcase the whole algorithm:\n\n```bash\n# Encryption:\n\n      h       e       l       l       o  message\n   7 (h)   4 (e)  11 (l)  11 (l)  14 (o) message\n+ 23 (X)  12 (M)   2 (C)  10 (K)  11 (L) key\n= 30      16      13      21      25     message + key\n=  4 (E)  16 (Q)  13 (N)  21 (V)  25 (Z) (message + key) mod 26\n      E       Q       N       V       Z  → ciphertext\n\n# Decryption:\n\n       E       Q       N       V       Z  ciphertext\n    4 (E)  16 (Q)  13 (N)  21 (V)  25 (Z) ciphertext\n−  23 (X)  12 (M)   2 (C)  10 (K)  11 (L) key\n= −19       4      11      11      14     ciphertext – key\n=   7 (h)   4 (e)  11 (l)  11 (l)  14 (o) ciphertext – key + length_alphabets (if less than zero)\n       h       e       l       l       o  → message\n```\n\n## Features\n\nGeneral:\n\n- **No dependencies.** Only needs standard Go and no dependencies are required.\n- **Battle-tested.** This library conforms to the standard library.\n- **Lightweight.** Small in size due to not having any dependencies.\n- **Secure.** Tries its best to implement as many security considerations as possible with careful and secure coding practices.\n- **Single Responsibility Principle (SRP)**. Every function in this library will do only one thing only.\n- **100% tested.** As this library is small, the code coverage is still 100% for now.\n- **Well documented.** Check out this `README.md` document and the technical documentation for further reading!\n\nSpecific:\n\n- **Supports custom alphabets.** By default, Vigenère-Vernam Cipher only supports Latin alphabets A to Z, all in uppercase. This library allows you to use custom alphabets by defining the character set. You can use numbers, lowercase characters, and even symbols. Because we are using slices, these custom alphabets are implemented without reducing the overall security of the library (without inadvertently creating modulo bias, error in calculations, and others).\n- **Strong random secret.** We use Golang's `crypto/rand`'s `rand.Int`, which takes the numbers from the hardware noise (`/dev/urandom` in Linux). This is by no means a perfect, true random number generator, but it can at least be cryptographically secure. The secret also has to be at least the length of the plaintext to prevent weak keys, as our goal with this library is also to make it as a One-Time Pad. Random secret in `*Vigenere` implements the `io.Reader` interface. You may replace it if needs arise.\n\n## Documentation\n\nComplete documentation could be seen in the official [pkg.go.dev site](https://pkg.go.dev/github.com/lauslim12/vigenere).\n\n## Installation\n\nI am going to assume that you are using Go version 1.18.\n\n- Download this library.\n\n```bash\ngo install github.com/lauslim12/vigenere\n\n# or: go get -u github.com/lauslim12/vigenere\n```\n\n- Import in your source code.\n\n```go\nimport \"github.com/lauslim12/vigenere\"\n```\n\n- Instantiate the `Vigenere` structure in your code, and define your plaintext.\n\n```go\nvigenere, err := vigenere.NewVigenere(nil) // Use default alphabets (A - Z in uppercase).\nif err != nil {\n    log.Fatal(err.Error())\n}\n\nplaintext := \"PLAINTEXT\"\n```\n\n- The steps are to validate your string, generate your own secret with pseudorandom number generator, encrypt your string, then convert it to the number equivalent. The steps are made like this so there would be no invalid inputs, and so the library would conform to Single Responbility Principle for each of the functions.\n\n```go\nvalid, err := vigenere.ValidateString(plaintext)\nif err != nil {\n    log.Fatal(err.Error())\n}\n\nkey, err := vigenere.GenerateSecretKey(plaintext)\nif err != nil {\n    log.Fatal(err.Error())\n}\n\nciphertext, err := vigenere.Encrypt(plaintext, key)\nif err != nil {\n    log.Fatal(err.Error())\n}\n\nfmt.Println(ciphertext)\n```\n\n- Done! If you want, feel free to look at tests (`vigenere_test.go`, run by using `go test -cover ./... ./...`) and the source code itself.\n\n## Notes\n\nSeveral notes if you want to understand the engineering decisions that I have made during the creation of this library:\n\n- **What happens if one step, let's say the string validation is skipped?**\n\nThe program may panic (runtime error, usually the error is slice index out of range, that happens if a text contains a rune/letter that does not exist in the character set or alphabets) if the input does not conform to the parameters. That's why string validation is important. Please use the provided `vigenere.ValidateString(str string)` to validate your string before inputting them to any of the methods.\n\n- **Wouldn't it be better to use `rune` and ASCII characters instead of using slices for the alphabets?**\n\nI have thought about using ASCII characters. It can be done by subtracting with `65` to get the numerical representative for the `A` character (we assume that A is zero). I also have no need to create slices if I use ASCII characters. However, it comes at a cost, that is: I cannot use custom alphabets for the cipher. If I use `string` and slices, using custom alphabets is more than possible.\n\n- **Why the time and space complexity can be so high? `O(N)` and `O(N^2)` seems a bit over the top.**\n\nThe time complexity is a bit high because of the utilization of slices. I prefer to use slices over `map[string]int64` as slices are simpler and I believe it is enough for this use-case. I don't think someone wants to encrypt a string with over 1.000.000 runes / letters as its character set. If I were to use the ASCII style as above, I would be able to reach `O(1)` efficiency, but we would not be able to use custom alphabets.\n\n## Examples\n\nPlease see examples at [the example project (`example/main.go`)](./example). You may run it by using `go run example/main.go` and the results will be shown instantly.\n\n## Contributing\n\nThis tool is open source and the contribution of this tool is highly encouraged! If you want to contribute to this project, please feel free to read the `CONTRIBUTING.md` file for the contributing guidelines.\n\n## License\n\nThis work is licensed under MIT License. Please check the `LICENSE` file for more information.\n\n## References\n\nHere are the references that I have used to write this library:\n\n- [How is One-Time Pad Perfectly Secure](https://crypto.stackexchange.com/questions/31084/how-is-the-one-time-pad-otp-perfectly-secure)\n- [Is Modern Encryption Needlessly Complicated?](https://crypto.stackexchange.com/questions/596/is-modern-encryption-needlessly-complicated)\n- [One-Time Pad Example](https://www.boxentriq.com/code-breaking/one-time-pad)\n- [One-Time Pad Example Calculation](https://en.wikipedia.org/wiki/One-time_pad)\n- [Why One-Time Pad is Useless in Practice](https://crypto.stackexchange.com/questions/15652/one-time-pad-why-is-it-useless-in-practice)\n- [Why is One-Time Pad not Vulerable to Brute-Force Attacks?](https://crypto.stackexchange.com/questions/596/is-modern-encryption-needlessly-complicated)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flauslim12%2Fvigenere","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flauslim12%2Fvigenere","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flauslim12%2Fvigenere/lists"}