Advertisement
cduclaux

RC4-256 Cipher Pure Lua

Dec 6th, 2014
280
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 10.05 KB | None | 0 0
  1. --[[
  2. Copyright (C) 2014 Clinton Duclaux [clinton at diceserver dot ca]
  3.  
  4. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
  5. associated documentation files (the "Software"), to deal in the Software without restriction,
  6. including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
  7. copies of the Software, and to permit persons to whom the Software is furnished to do so,
  8. subject to the following conditions:
  9.  
  10. -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  11. -Visible credit is given to the original author.
  12. -The software is distributed in a non-profit way.
  13.  
  14. ---------------------------------------------------------------------------------------------------------------------------------
  15.  
  16. This library will do an RC4-256 stream cipher. The function list is as below
  17.  
  18. encryptRC4(msg, key)    --Encrypts @msg with @key and then does a base32 transform on the output value
  19. decryptRC4(msg, key)    --Decrypts @msg with @key, @msg is first debased32 transformed before it is decrypted
  20. rc4(msg, key)           --Encrypts @msg with @key
  21. swap (x, y)             --Swaps @x and @y
  22.  
  23. This is a pure lua implementation of the RC4 stream cipher. This implementation only does raw encryption and decryption.
  24. That is; it does not have any mechanism upon decryption to ensure that a correct key was used. If an incorrect key
  25. is used it will give garbage out which may include special character. It is advised you do integrity checking to ensure that
  26. your decrypted message has been in fact decrypted with a valid key. The output ciphertext will come out base32 encoded. The base32
  27. encoding IS NOT an encryption mechanism, rather it is a way to make binary data human readable. Conversely when you decrypt a message
  28. the decryptRC4 function expects a base32 message.
  29.  
  30. If you want to deal with the raw RC4 algorithm call the rc4 function directly.  The function is the same for both encryption and
  31. decryption
  32.  
  33. **************************************************** SECURITY **************************************************************
  34. The RC4-256 cipher has several weaknesses that are inherent to Output Feedback mode ciphers. Repeat after me:
  35.                              
  36.                                 NEVER USE THE SAME KEY TO ENCRYPT TWO DIFFERENT MESSAGES
  37.                                
  38. If you do, you completely break the security of the system. Here's why: if you have two ciphertext streams, A+K and B+K,
  39. and you subtract one from the other, you get (A+K)-(B+K) = A+K-B-K = A-B. That's two plaintext streams combined with each other
  40. with no key involved, and is very easy to break. Trust me on this one: you might not be able to recover A and B from A-B, but a
  41. professional cryptanalyst can. This is vitally important: never use the same key to encrypt two different messages.
  42. For more information on this weakness please see the following website, while it speaks to the solitaire cipher it should be noted
  43. that RC4 like solitaire is an Output Feedback Ciphers.
  44. https://www.schneier.com/solitaire.html
  45.  
  46. Stream ciphers can include other weaknesses such as bit-flipping attacks.  Do your research and ensure that this cipher will meet
  47. your needs. If your trying to protect your messages from your kid brother it will probably be more than enough. If you are trying
  48. to protect your messages from a motivated government or corporation you would be best advised to look at better ciphers.
  49.  
  50. You are responsible for ensuring your keys are strong. As this is a pure implementation nonce's are not implemented. This
  51. creates a situation where if you use weak keys your encryption may be easily brute forced. It needs to be said again.
  52. You must use strong keys to prevent brute force attacks.
  53.  
  54. ***************************************************************************************************************************
  55.  
  56. The following functions are not my work and I give credit where it is due.
  57.  
  58. Copyright (C) 2012 Thomas Farr a.k.a tomass1996 [farr.thomas@gmail.com]
  59.  
  60. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
  61. associated documentation files (the "Software"), to deal in the Software without restriction,
  62. including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
  63. copies of the Software, and to permit persons to whom the Software is furnished to do so,
  64. subject to the following conditions:
  65.  
  66. -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  67. -Visible credit is given to the original author.
  68. -The software is distributed in a non-profit way.
  69.  
  70. toBase32(str)       --Encodes @str in Base32
  71. fromBase32(str)     --Decodes @str from Base32
  72. bit.tobits(n)       --Transform @n to bits
  73. bit.tonumb(n)       --Transform @tbl bits to number
  74. bit.bxor(m,n)       --Xor's @m, @n bits tables
  75. bit.checkint(n)     --Sanity checks @n to make sure we do a bitwise on a number only
  76. bit.expand(m, n)    --Expands tables so we can xor them
  77.  
  78. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  79. WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  80. COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  81. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  82. ]]--
  83.  
  84. function encryptRC4(msg, key)
  85.     return(toBase32(rc4(msg, key)))
  86. end
  87.  
  88. --the decryption is done by RC4, the fromBase32 is only used for human readability
  89. -- it also has the effect that we don't need to do any escaping of the string when we pass it around
  90. function decryptRC4(msg, key)
  91.     return(rc4(fromBase32(msg), key))
  92. end
  93.  
  94. function rc4(msg, key)
  95.  
  96.     --ensure the inputs are strings if they are already not
  97.     str = tostring(str)
  98.     key = tostring(key)
  99.  
  100.     --Our output string, we will build this as we go when we do our RC4 transform
  101.     out = ""
  102.  
  103.     --S Boxes, used in keeping track of the key schedule values
  104.     S = {}    
  105.    
  106.     -- Key scheduling
  107.     -- initialize our S table
  108.     for i = 0, 255, 1 do
  109.         S[i] = i
  110.     end
  111.    
  112.     -- Do the key scheduling, this will use our key to scramble up initalize and scramble the S-Boxes,
  113.     -- The key scheduling does not use a nonce so you as the user are responsible for making sure the
  114.     --keys are strong
  115.     j = 0
  116.     for i = 0, 255, 1 do
  117.         j = (j + S[i] + key:byte((i%key:len())+1))%256
  118.         S[i], S[j] = swap(S[i], S[j]) -- swap S[i] and S[j]
  119.     end
  120.  
  121.     -- Encrypt/Decrypt our message
  122.     i = 0
  123.     j = 0
  124.     for k = 1, msg:len(), 1 do -- loop k times which is the length of our input
  125.        i = (i + 1) % 256
  126.        j = (j + S[i]) % 256
  127.        S[i], S[j] = swap(S[i], S[j]) -- swap S[i] and S[j]
  128.        K = S[(S[i] + S[j]) % 256]
  129.  
  130.        --encrypt/decrypt our byte and put into our output string
  131.        out = out .. string.char(bit.bxor(msg:byte(i), K))
  132.     end    
  133.    
  134.     return out
  135. end
  136.  
  137. function swap(x, y)
  138.     return y, x
  139. end
  140.  
  141. --the encryption is done by RC4, the toBase32 is only used to take our string that can include special characters and makes them
  142. --human readable, it also has the effect that we don't need to do any escaping of the string when we pass it around
  143.  
  144. local base32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
  145.  
  146. function toBase32(str)  --Encodes @str in Base32
  147.     if not str then return nil end
  148.     str = tostring(str)
  149.     local byte=0
  150.     local bits=0
  151.     local rez=""
  152.     local i=0
  153.     for i = 1, str:len() do
  154.         byte=byte*256+str:byte(i)
  155.         bits=bits+8
  156.         repeat
  157.             bits=bits-5
  158.             local mul=(2^(bits))
  159.             local b32n=math.floor(byte/mul)
  160.             byte=byte-(b32n*mul)
  161.             b32n=b32n+1
  162.             rez=rez..string.sub(base32,b32n,b32n)
  163.         until bits<5
  164.     end
  165.     if bits>0 then
  166.         local b32n= math.fmod(byte*(2^(5-bits)),32)
  167.         b32n=b32n+1
  168.         rez=rez..string.sub(base32,b32n,b32n)
  169.     end
  170.     return rez
  171. end
  172.  
  173. function fromBase32(str)  --Decodes @str from Base32
  174.     if not str then return nil end
  175.     str = tostring(str)
  176.     local b32n=0
  177.     local bits=0
  178.     local rez=""
  179.     local i=0
  180.     string.gsub(str:upper(), "["..base32.."]", function (char)
  181.         local num = string.find(base32, char, 1, true)
  182.         b32n=b32n*32+(num - 1)
  183.         bits=bits+5
  184.         while  bits>=8 do
  185.             bits=bits-8
  186.             local mul=(2^(bits))
  187.             local byte = math.floor(b32n/mul)
  188.             b32n=b32n-(byte*mul)
  189.             rez=rez..string.char(byte)
  190.         end
  191.     end)
  192.     return rez
  193. end
  194.  
  195.  
  196. local bit = {}
  197.  
  198. bit["tobits"] = function(n)
  199.     bit.checkint(n)
  200.     if(n < 0) then
  201.         return bit.tobits(bit.bnot(math.abs(n)) + 1)
  202.     end
  203.     local tbl = {}
  204.     local cnt = 1
  205.     while (n > 0) do
  206.         local last = math.fmod(n,2)
  207.         if(last == 1) then
  208.             tbl[cnt] = 1
  209.         else
  210.             tbl[cnt] = 0
  211.         end
  212.         n = (n-last)/2
  213.         cnt = cnt + 1
  214.     end
  215.     return tbl
  216. end
  217.  
  218. bit["tonumb"] = function(tbl)
  219.     local n = table.getn(tbl)
  220.     local rslt = 0
  221.     local power = 1
  222.     for i = 1, n do
  223.         rslt = rslt + tbl[i]*power
  224.         power = power*2
  225.     end
  226.     return rslt
  227. end
  228.  
  229. bit["bxor"] = function(m, n)
  230.     local tbl_m = bit.tobits(m)
  231.     local tbl_n = bit.tobits(n)
  232.     bit.expand(tbl_m, tbl_n)
  233.     local tbl = {}
  234.     local rslt = math.max(table.getn(tbl_m), table.getn(tbl_n))
  235.     for i = 1, rslt do
  236.         if(tbl_m[i] ~= tbl_n[i]) then
  237.             tbl[i] = 1
  238.         else
  239.             tbl[i] = 0
  240.         end
  241.     end
  242.     return bit.tonumb(tbl)
  243. end
  244.  
  245. bit["checkint"] = function(n)
  246.     if(n - math.floor(n) > 0) then
  247.         error("trying to use bitwise operation on non-integer!")
  248.     end
  249. end
  250.  
  251. bit["expand"] = function(tbl_m, tbl_n)
  252.     local big = {}
  253.     local small = {}
  254.     if(table.getn(tbl_m) > table.getn(tbl_n)) then
  255.         big = tbl_m
  256.         small = tbl_n
  257.     else
  258.         big = tbl_n
  259.         small = tbl_m
  260.     end
  261.     for i = table.getn(small) + 1, table.getn(big) do
  262.         small[i] = 0
  263.     end
  264. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement