Skip to content

Instantly share code, notes, and snippets.

@mohitkhanna
Forked from rhoot/rc4.coffee
Last active September 22, 2015 08:26
Show Gist options
  • Save mohitkhanna/5a4bfbc1d1285b4bab93 to your computer and use it in GitHub Desktop.
Save mohitkhanna/5a4bfbc1d1285b4bab93 to your computer and use it in GitHub Desktop.
Node.js RC4 encryption/decryption
###
Copyright (c) 2012 rhoot <https://github.com/rhoot>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
###
###
Sample usage:
rc4 = require 'rc4'
engine = new rc4.Engine()
# Encrypt 'Plaintext' with key 'Key'.
# 'encrypted' contains a node.js Buffer with the results
engine.init 'Key'
encrypted = engine.encrypt 'Plaintext'
# Encryption also works on byte arrays and node.js Buffer objects
# This would give the same results as the above
engine.init [ 0x4b, 0x65, 0x79 ]
encrypted = engine.encrypt new Buffer([ 0x50, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74 ])
# Decrypting is just as easy 'Attack at dawn' with key 'Secret'
engine.init 'Secret'
message = [ 0x45, 0xA0, 0x1F, 0x64, 0x5F, 0xC3, 0x5B, 0x38, 0x35, 0x52, 0x54, 0x4B, 0x9B, 0xF5 ]
decrypted = engine.decrypt(message).toString()
# Some encrypted messages require dropping the first x bytes of the keystream.
engine.init 'Key'
engine.drop 3072
decrypted = engine.decrypt [ 0x36, 0x49, 0xbe, 0xa0, 0xdf, 0xb1, 0xd3, 0xcd, 0x3f ]
###
isArrayIsh = (obj) ->
Array.isArray(obj) or
Buffer.isBuffer(obj) or
(obj? and typeof obj is 'object' and typeof obj.length is 'number')
stringToArray = (str) ->
str.charCodeAt i for i in [0...str.length]
class Rc4Engine
# @public
constructor: (key) ->
@state = new Array 256
@i1 = 0
@i2 = 0
@init key if key?
# @private
swap = (state, i1, i2) ->
temp = state[i1]
state[i1] = state[i2]
state[i2] = temp
# @private
step = (e) ->
e.i1 = (e.i1 + 1) & 255
e.i2 = (e.i2 + e.state[e.i1]) & 255
swap e.state, e.i1, e.i2
# @public
init: (key) ->
key = stringToArray key if typeof key is 'string'
throw new TypeError 'Invalid key type' if not isArrayIsh key
@state = [0...256]
@i1 = 0
@i2 = 0
j = 0
for i in [0...256]
j = (j + @state[i] + key[i % key.length]) & 255
swap @state, i, j
# @public
drop: (num) ->
throw new TypeError 'Invalid num argument.' unless typeof num is 'number'
step this for i in [0...num]
# @public
encrypt: (bytes) ->
bytes = stringToArray bytes if typeof bytes is 'string'
throw new TypeError 'Invalid data type.' if not isArrayIsh bytes
encrypted = new Buffer bytes.length
for i in [0...bytes.length]
step this
key = @state[(@state[@i1] + @state[@i2]) & 0xff]
encrypted[i] = bytes[i] ^ key
encrypted
# @public
decrypt: (bytes) ->
# RC4 encryption and decryption algorithms are exactly the same
@encrypt bytes
module.exports =
Engine: Rc4Engine
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment