module std::crypto::rc4; // Copyright (c) 2021 Christoffer Lerno. All rights reserved. // Use of this source code is governed by the MIT license // a copy of which can be found in the LICENSE_STDLIB file. struct Rc4 { uint i, j; char[256] state; } /** * Initialize the RC4 state. * * @param [in] key "The key to use" * @require key.len > 0 "The key must be at least 1 byte long" **/ fn void Rc4.init(&self, char[] key) { // Init the state matrix foreach (char i, &c : self.state) *c = i; for (int i = 0, int j = 0; i < 256; i++) { j = (j + self.state[i] + key[i % key.len]) & 0xFF; @swap(self.state[i], self.state[j]); } self.i = 0; self.j = 0; } /** * Run a single pass of en/decryption using a particular key. * @param [in] key * @param [inout] data **/ fn void crypt(char[] key, char[] data) { Rc4 rc4; rc4.init(key); rc4.crypt(data, data); } /** * Encrypt or decrypt a sequence of bytes. * * @param [in] in "The input" * @param [out] out "The output" * @require in.len <= out.len "Output would overflow" **/ fn void Rc4.crypt(&self, char[] in, char[] out) { uint i = self.i; uint j = self.j; char* state = &self.state; isz len = in.len; foreach (idx, c : in) { i = (i + 1) & 0xFF; j = (j + state[i]) & 0xFF; @swap(state[i], state[j]); out[idx] = in[idx] ^ state[(state[i] + state[j]) & 0xFF]; } self.i = i; self.j = j; } /** * Clear the rc4 state. * * @param [&out] self "The RC4 State" **/ fn void Rc4.destroy(&self) { *self = {}; }