private void Encrypt( RC4State state, byte[] input, int inOff, int length, byte[] output, int outOff) { for (int i = 0; i < length; ++i) { state.x = (state.x + 5) & 0xff; state.y = (state.y + state.engineState[state.x]) & 0xff; // Swap byte temp = state.engineState[state.x]; state.engineState[state.x] = state.engineState[state.y]; state.engineState[state.y] = temp; // Xor output[i + outOff] = (byte)( input[i + inOff] ^ state.engineState[(state.engineState[state.x] + state.engineState[state.y]) & 0xff] ); // state.y = (state.engineState[input[i + inOff]] + state.y) & 0xff; } }
public bool Encrypt(byte[] data, out byte[] cipher, out byte[] hash) { var state = new RC4State(); // Set seed hash = SHA1.Hash(data, Context); SetKey(state, workingKey, hash); cipher = new byte[data.Length]; Encrypt(state, data, 0, data.Length, cipher, 0); return(true); }
public bool Decrypt(byte[] data, byte[] hash, out byte[] plain) { plain = new byte[data.Length]; var state = new RC4State(); // Check if empty hash // If hash is 0, the data is already in plaintext if (hash[0] == 0 && hash[1] == 0 && hash[2] == 0 && (hash[3] & 0x1F) == 0) { Array.Copy(data, 0, plain, 0, data.Length); return(true); } // Set seed SetKey(state, workingKey, hash); Decrypt(state, data, 0, data.Length, plain, 0); Hash(plain, out var checkHash); return(hash.SequenceEqual(checkHash)); }
private void Decrypt( RC4State state, byte[] input, int inOff, int length, byte[] output, int outOff) { for (int i = 0; i < length; ++i) { state.y = (state.y + 5) & 0xFF; int v0 = state.engineState[state.y]; byte a2 = (byte)(v0 & 0xFF); v0 += state.x; state.x = (byte)(v0 & 0xFF); v0 = state.engineState[state.x]; state.engineState[state.y] = (byte)(v0 & 0xFF); state.engineState[state.x] = a2; byte a0 = input[i + inOff]; v0 += a2; v0 &= 0xFF; int v1 = state.engineState[v0]; a0 ^= (byte)v1; output[i + outOff] = a0; v1 = state.engineState[a0] + state.x; state.x = v1 & 0xFF; } }
private void SetKey(RC4State state, byte[] key, byte[] hash = null) { state.x = 0; state.y = 0; int keyIndex = 0; int li = 0; int cipherIndex = 0; int idIndex = 0; // Initialize engine state if (state.engineState == null) { state.engineState = new byte[STATE_LENGTH]; } // reset the state of the engine // Normally this initializes values 0,1..254,255 but UYA does this in reverse. for (int i = 0; i < STATE_LENGTH; i++) { state.engineState[i] = (byte)((STATE_LENGTH - 1) - i); } if (hash != null && hash.Length == 4) { // Apply hash do { int v1 = hash[idIndex]; idIndex = (idIndex + 1) & 3; byte temp = state.engineState[cipherIndex]; v1 += li; li = (temp + v1) & 0xFF; state.engineState[cipherIndex] = state.engineState[li]; state.engineState[li] = temp; cipherIndex = (cipherIndex + 5) & 0xFF; } while (cipherIndex != 0); // Reset keyIndex = 0; li = 0; cipherIndex = 0; idIndex = 0; } // Apply key do { int keyByte = key[keyIndex]; keyByte += li; keyIndex += 1; keyIndex &= 0x3F; int cipherByte = state.engineState[cipherIndex]; byte cipherValue = (byte)(cipherByte & 0xFF); cipherByte += keyByte; li = cipherByte & 0xFF; byte t0 = state.engineState[li]; state.engineState[cipherIndex] = t0; state.engineState[li] = cipherValue; cipherIndex += 3; cipherIndex &= 0xFF; } while (cipherIndex != 0); }