# HG changeset patch # User Matthew Wild # Date 1297888173 0 # Node ID 598d09faf89c6a19778a82f215f76825a9e7406a There are no secrets better kept than the secrets that everybody guesses. diff -r 000000000000 -r 598d09faf89c COPYING --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/COPYING Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,20 @@ +Copyright (c) 2011 Matthew Wild +(excluding aeslua - see README) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff -r 000000000000 -r 598d09faf89c README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,17 @@ +YubiKey token parsing and validation for Lua +--- --- --- --- --- ---- --- --- --- --- --- + +This library allows you to parse OTP tokens from a YubiKey +device, and also provides a validation framework for people +who want to integrate OTP authentication into their applications. + +\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ +NOTE: This project is MIT/X11 licensed - however the project > + contains modified parts of aeslua, which is LGPL-licensed. > + Since LGPL is more restrictive than MIT, you should take > + care to obey its requirements when using yubikey.lua in > + your projects. See the docs in aeslua/ for more details. > +/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + +The easiest way to use this library is to run 'squish' in its +directory. Squish can be found at http://matthewwild.co.uk/projects/squish diff -r 000000000000 -r 598d09faf89c aeslua/Copyright.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/aeslua/Copyright.txt Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,26 @@ +aeslua: Lua AES implementation +Copyright (c) 2006,2007 Matthias Hilbig + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser Public License as published by the +Free Software Foundation; either version 2.1 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser Public License for more details. + +A copy of the terms and conditions of the license can be found in +License.txt or online at + + http://www.gnu.org/copyleft/lesser.html + +To obtain a copy, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Author +------- +Matthias Hilbig +http://homepages.upb.de/hilbig/aeslua/ +hilbig@upb.de diff -r 000000000000 -r 598d09faf89c aeslua/License.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/aeslua/License.txt Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,450 @@ +---------------------------------------------------------------------- +The aeslua (all versions) is provided under the terms and +conditions of the GNU Lesser General Public Library, which is stated +below. It can also be found at: + + http://www.gnu.org/copyleft/lesser.html + +---------------------------------------------------------------------- + +GNU LESSER GENERAL PUBLIC LICENSE + +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts +as the successor of the GNU Library Public License, version 2, hence the +version number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public Licenses are +intended to guarantee your freedom to share and change free software--to +make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the Free +Software Foundation and other authors who decide to use it. You can use +it too, but we suggest you first think carefully about whether this +license or the ordinary General Public License is the better strategy to +use in any particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish); that you receive source code or can get it if +you want it; that you can change the software and use pieces of it in +new free programs; and that you are informed that you can do these +things. + +To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for you +if you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or +for a fee, you must give the recipients all the rights that we gave you. +You must make sure that they, too, receive or can get the source code. +If you link other code with the library, you must provide complete +object files to the recipients, so that they can relink them with the +library after making changes to the library and recompiling it. And you +must show them these terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is +no warranty for the free library. Also, if the library is modified by +someone else and passed on, the recipients should know that what they +have is not the original version, so that the original author's +reputation will not be affected by problems that might be introduced by +others. + +Finally, software patents pose a constant threat to the existence of any +free program. We wish to make sure that a company cannot effectively +restrict the users of a free program by obtaining a restrictive license +from a patent holder. Therefore, we insist that any patent license +obtained for a version of the library must be consistent with the full +freedom of use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License. This license, the GNU Lesser General Public +License, applies to certain designated libraries, and is quite different +from the ordinary General Public License. We use this license for +certain libraries in order to permit linking those libraries into +non-free programs. + +When a program is linked with a library, whether statically or using a +shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the entire +combination fits its criteria of freedom. The Lesser General Public +License permits more lax criteria for linking other code with the +library. + +We call this license the "Lesser" General Public License because it does +Less to protect the user's freedom than the ordinary General Public +License. It also provides other free software developers Less of an +advantage over competing non-free programs. These disadvantages are the +reason we use the ordinary General Public License for many libraries. +However, the Lesser license provides advantages in certain special +circumstances. + +For example, on rare occasions, there may be a special need to encourage +the widest possible use of a certain library, so that it becomes a +de-facto standard. To achieve this, non-free programs must be allowed to +use the library. A more frequent case is that a free library does the +same job as widely used non-free libraries. In this case, there is +little to gain by limiting the free library to free software only, so we +use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of free +software. For example, permission to use the GNU C Library in non-free +programs enables many more people to use the whole GNU operating system, +as well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is linked +with the Library has the freedom and the wherewithal to run that program +using a modified version of the Library. + +The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or other +authorized party saying it may be distributed under the terms of this +Lesser General Public License (also called "this License"). Each +licensee is addressed as "you". + +A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which +has been distributed under these terms. A "work based on the Library" +means either the Library or any derivative work under copyright law: +that is to say, a work containing the Library or a portion of it, either +verbatim or with modifications and/or translated straightforwardly into +another language. (Hereinafter, translation is included without +limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making +modifications to it. For a library, complete source code means all the +source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and +installation of the library. + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of running +a program using the Library is not restricted, and output from such a +program is covered only if its contents constitute a work based on the +Library (independent of the use of the Library in a tool for writing +it). Whether that is true depends on what the Library does and what the +program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the notices +that refer to this License and to the absence of any warranty; and +distribute a copy of this License along with the Library. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of +it, thus forming a work based on the Library, and copy and distribute +such modifications or work under the terms of Section 1 above, provided +that you also meet all of these conditions: + + a) The modified work must itself be a software library. + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has +a purpose that is entirely well-defined independent of the application. +Therefore, Subsection 2d requires that any application-supplied function +or table used by this function must be optional: if the application does +not supply it, the square root function must still compute square +roots.) + + These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, and +can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based on +the Library, the distribution of the whole must be on the terms of this +License, whose permissions for other licensees extend to the entire +whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or +contest your rights to work written entirely by you; rather, the intent +is to exercise the right to control the distribution of derivative or +collective works based on the Library. + + In addition, mere aggregation of another work not based on the +Library with the Library (or with a work based on the Library) on a +volume of a storage or distribution medium does not bring the other work +under the scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so that +they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in these +notices. + +Once this change is made in a given copy, it is irreversible for that +copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the +Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative +of it, under Section 2) in object code or executable form under the +terms of Sections 1 and 2 above provided that you accompany it with the +complete corresponding machine-readable source code, which must be +distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a +designated place, then offering equivalent access to copy the source +code from the same place satisfies the requirement to distribute the +source code, even though third parties are not compelled to copy the +source along with the object code. + +5. A program that contains no derivative of any portion of the Library, +but is designed to work with the Library by being compiled or linked +with it, is called a "work that uses the Library". Such a work, in +isolation, is not a derivative work of the Library, and therefore falls +outside the scope of this License. + +However, linking a "work that uses the Library" with the Library creates +an executable that is a derivative of the Library (because it contains +portions of the Library), rather than a "work that uses the library". +The executable is therefore covered by this License. Section 6 states +terms for distribution of such executables. + +When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be linked +without the Library, or if the work is itself a library. The threshold +for this to be true is not precisely defined by law. + +If such an object file uses only numerical parameters, data structure +layouts and accessors, and small macros and small inline functions (ten +lines or less in length), then the use of the object file is +unrestricted, regardless of whether it is legally a derivative work. +(Executables containing this object code plus portions of the Library +will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, whether +or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a +"work that uses the Library" with the Library to produce a work +containing portions of the Library, and distribute that work under terms +of your choice, provided that the terms permit modification of the work +for the customer's own use and reverse engineering for debugging such +modifications. + +You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work during +execution displays copyright notices, you must include the copyright +notice for the Library among them, as well as a reference directing the +user to the copy of this License. Also, you must do one of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood that + the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + +For an executable, the required form of the "work that uses the Library" +must include any data and utility programs needed for reproducing the +executable from it. However, as a special exception, the materials to be +distributed need not include anything that is normally distributed (in +either source or binary form) with the major components (compiler, +kernel, and so on) of the operating system on which the executable runs, +unless that component itself accompanies the executable. + +It may happen that this requirement contradicts the license restrictions +of other proprietary libraries that do not normally accompany the +operating system. Such a contradiction means you cannot use both them +and the Library together in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library +side-by-side in a single library together with other library facilities +not covered by this License, and distribute such a combined library, +provided that the separate distribution of the work based on the Library +and of the other library facilities is otherwise permitted, and provided +that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the +Library except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense, link with, or distribute the +Library is void, and will automatically terminate your rights under this +License. However, parties who have received copies, or rights, from you +under this License will not have their licenses terminated so long as +such parties remain in full compliance. + +9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and all +its terms and conditions for copying, distributing or modifying the +Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + +11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot distribute +so as to satisfy simultaneously your obligations under this License and +any other pertinent obligations, then as a consequence you may not +distribute the Library at all. For example, if a patent license would +not permit royalty-free redistribution of the Library by all those who +receive copies directly or indirectly through you, then the only way you +could satisfy both it and this License would be to refrain entirely from +distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is implemented +by public license practices. Many people have made generous +contributions to the wide range of software distributed through that +system in reliance on consistent application of that system; it is up to +the author/donor to decide if he or she is willing to distribute +software through any other system and a licensee cannot impose that +choice. + +This section is intended to make thoroughly clear what is believed to be +a consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may +add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among countries +not thus excluded. In such case, this License incorporates the +limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions +of the Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a license +version number, you may choose any version ever published by the Free +Software Foundation. + +14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free Software +Foundation; we sometimes make exceptions for this. Our decision will be +guided by the two goals of preserving the free status of all derivatives +of our free software and of promoting the sharing and reuse of software +generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH +YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR +DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY +(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED +INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF +THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR +OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. diff -r 000000000000 -r 598d09faf89c aeslua/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/aeslua/README Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,48 @@ +AES for lua +----------- + +This files contain an implementation of AES in lua. The only additional library +needed is bitlib. + +Usage +----- + +aeslua.lua contains a simple API to encrypt and decrypt lua strings. + +To encrypt the string "geheim" with the password "password" use: + +require("aeslua"); +cipher = aeslua.encrypt("password", "secret"); + +and to decrypt the string again: + +plain = aeslua.decrypt("password", cipher); + +You can also specify the key size and the encryption mode. For further examples +look into the file src/testcryptotest.lua. + +To use AES directly, have a look at aes.lua and at the example usage in +testaes.lua. + +Installation +------------ + +Edit the LIBDIR variable in the Makefile and run + +make install + +Speed +----- + +The implementation is rather optimized (it uses tables for most AES operations) +but still cannot compete with AES written in other languages. Typical AES +implementations reach several 100 MBit per second, this implementation only +reaches 400 kBit per second. The most plausible reason is the heavy reliance +of AES on bit operations. As lua numbers are doubles bitlib needs to convert +them to long values for each bit operation. + +So if you need to encrypt much data with AES, do yourself a favor and use a +C-Implementation. But if you only need to encrypt short strings and you have +no control over the lua environment (like in games :-)) use this library. + +Matthias Hilbig (hilbig@upb.de) diff -r 000000000000 -r 598d09faf89c aeslua/aes.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/aeslua/aes.lua Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,509 @@ +local bit = require("bit"); + +local gf = require("aeslua.gf"); +local util = require("aeslua.util"); + +-- +-- Implementation of AES with nearly pure lua (only bitlib is needed) +-- +-- AES with lua is slow, really slow :-) +-- + +local public = {}; +local private = {}; + +local aeslua = require("aeslua"); +aeslua.aes = public; + +-- some constants +public.ROUNDS = "rounds"; +public.KEY_TYPE = "type"; +public.ENCRYPTION_KEY=1; +public.DECRYPTION_KEY=2; + +-- aes SBOX +private.SBox = {}; +private.iSBox = {}; + +-- aes tables +private.table0 = {}; +private.table1 = {}; +private.table2 = {}; +private.table3 = {}; + +private.tableInv0 = {}; +private.tableInv1 = {}; +private.tableInv2 = {}; +private.tableInv3 = {}; + +-- round constants +private.rCon = {0x01000000, + 0x02000000, + 0x04000000, + 0x08000000, + 0x10000000, + 0x20000000, + 0x40000000, + 0x80000000, + 0x1b000000, + 0x36000000, + 0x6c000000, + 0xd8000000, + 0xab000000, + 0x4d000000, + 0x9a000000, + 0x2f000000}; + +-- +-- affine transformation for calculating the S-Box of AES +-- +function private.affinMap(byte) + local mask = 0xf8; + local result = 0; + for i = 1,8 do + result = bit.lshift(result,1); + + local parity = util.byteParity(bit.band(byte,mask)); + result = result + parity; + + -- simulate roll + local lastbit = bit.band(mask, 1); + mask = bit.band(bit.rshift(mask, 1),0xff); + if (lastbit ~= 0) then + mask = bit.bor(mask, 0x80); + else + mask = bit.band(mask, 0x7f); + end + end + + return bit.bxor(result, 0x63); +end + +-- +-- calculate S-Box and inverse S-Box of AES +-- apply affine transformation to inverse in finite field 2^8 +-- +function private.calcSBox() + local inverse; + for i = 0, 255 do + if (i ~= 0) then + inverse = gf.invert(i); + else + inverse = i; + end + local mapped = private.affinMap(inverse); + private.SBox[i] = mapped; + private.iSBox[mapped] = i; + end +end + +-- +-- Calculate round tables +-- round tables are used to calculate shiftRow, MixColumn and SubBytes +-- with 4 table lookups and 4 xor operations. +-- +function private.calcRoundTables() + for x = 0,255 do + local byte = private.SBox[x]; + private.table0[x] = util.putByte(gf.mul(0x03, byte), 0) + + util.putByte( byte , 1) + + util.putByte( byte , 2) + + util.putByte(gf.mul(0x02, byte), 3); + private.table1[x] = util.putByte( byte , 0) + + util.putByte( byte , 1) + + util.putByte(gf.mul(0x02, byte), 2) + + util.putByte(gf.mul(0x03, byte), 3); + private.table2[x] = util.putByte( byte , 0) + + util.putByte(gf.mul(0x02, byte), 1) + + util.putByte(gf.mul(0x03, byte), 2) + + util.putByte( byte , 3); + private.table3[x] = util.putByte(gf.mul(0x02, byte), 0) + + util.putByte(gf.mul(0x03, byte), 1) + + util.putByte( byte , 2) + + util.putByte( byte , 3); + end +end + +-- +-- Calculate inverse round tables +-- does the inverse of the normal roundtables for the equivalent +-- decryption algorithm. +-- +function private.calcInvRoundTables() + for x = 0,255 do + local byte = private.iSBox[x]; + private.tableInv0[x] = util.putByte(gf.mul(0x0b, byte), 0) + + util.putByte(gf.mul(0x0d, byte), 1) + + util.putByte(gf.mul(0x09, byte), 2) + + util.putByte(gf.mul(0x0e, byte), 3); + private.tableInv1[x] = util.putByte(gf.mul(0x0d, byte), 0) + + util.putByte(gf.mul(0x09, byte), 1) + + util.putByte(gf.mul(0x0e, byte), 2) + + util.putByte(gf.mul(0x0b, byte), 3); + private.tableInv2[x] = util.putByte(gf.mul(0x09, byte), 0) + + util.putByte(gf.mul(0x0e, byte), 1) + + util.putByte(gf.mul(0x0b, byte), 2) + + util.putByte(gf.mul(0x0d, byte), 3); + private.tableInv3[x] = util.putByte(gf.mul(0x0e, byte), 0) + + util.putByte(gf.mul(0x0b, byte), 1) + + util.putByte(gf.mul(0x0d, byte), 2) + + util.putByte(gf.mul(0x09, byte), 3); + end +end + + +-- +-- rotate word: 0xaabbccdd gets 0xbbccddaa +-- used for key schedule +-- +function private.rotWord(word) + local tmp = bit.band(word,0xff000000); + return (bit.lshift(word,8) + bit.rshift(tmp,24)) ; +end + +-- +-- replace all bytes in a word with the SBox. +-- used for key schedule +-- +function private.subWord(word) + return util.putByte(private.SBox[util.getByte(word,0)],0) + + util.putByte(private.SBox[util.getByte(word,1)],1) + + util.putByte(private.SBox[util.getByte(word,2)],2) + + util.putByte(private.SBox[util.getByte(word,3)],3); +end + +-- +-- generate key schedule for aes encryption +-- +-- returns table with all round keys and +-- the necessary number of rounds saved in [public.ROUNDS] +-- +function public.expandEncryptionKey(key) + local keySchedule = {}; + local keyWords = math.floor(#key / 4); + + + if ((keyWords ~= 4 and keyWords ~= 6 and keyWords ~= 8) or (keyWords * 4 ~= #key)) then + error("Invalid key size: "..keyWords); + return nil; + end + + keySchedule[public.ROUNDS] = keyWords + 6; + keySchedule[public.KEY_TYPE] = public.ENCRYPTION_KEY; + + for i = 0,keyWords - 1 do + keySchedule[i] = util.putByte(key[i*4+1], 3) + + util.putByte(key[i*4+2], 2) + + util.putByte(key[i*4+3], 1) + + util.putByte(key[i*4+4], 0); + end + + for i = keyWords, (keySchedule[public.ROUNDS] + 1)*4 - 1 do + local tmp = keySchedule[i-1]; + + if ( i % keyWords == 0) then + tmp = private.rotWord(tmp); + tmp = private.subWord(tmp); + + local index = math.floor(i/keyWords); + tmp = bit.bxor(tmp,private.rCon[index]); + elseif (keyWords > 6 and i % keyWords == 4) then + tmp = private.subWord(tmp); + end + + keySchedule[i] = bit.bxor(keySchedule[(i-keyWords)],tmp); + end + + return keySchedule; +end + +-- +-- Inverse mix column +-- used for key schedule of decryption key +-- +function private.invMixColumnOld(word) + local b0 = util.getByte(word,3); + local b1 = util.getByte(word,2); + local b2 = util.getByte(word,1); + local b3 = util.getByte(word,0); + + return util.putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b1), + gf.mul(0x0d, b2)), + gf.mul(0x09, b3)), + gf.mul(0x0e, b0)),3) + + util.putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b2), + gf.mul(0x0d, b3)), + gf.mul(0x09, b0)), + gf.mul(0x0e, b1)),2) + + util.putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b3), + gf.mul(0x0d, b0)), + gf.mul(0x09, b1)), + gf.mul(0x0e, b2)),1) + + util.putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b0), + gf.mul(0x0d, b1)), + gf.mul(0x09, b2)), + gf.mul(0x0e, b3)),0); +end + +-- +-- Optimized inverse mix column +-- look at http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf +-- TODO: make it work +-- +function private.invMixColumn(word) + local b0 = util.getByte(word,3); + local b1 = util.getByte(word,2); + local b2 = util.getByte(word,1); + local b3 = util.getByte(word,0); + + local t = bit.bxor(b3,b2); + local u = bit.bxor(b1,b0); + local v = bit.bxor(t,u); + v = bit.bxor(v,gf.mul(0x08,v)); + v = bit.bxor(v,gf.mul(0x04, bit.bxor(b3,b1))); + local w = bit.bxor(v,gf.mul(0x04, bit.bxor(b2,b0))); + + return util.putByte( bit.bxor(bit.bxor(b3,v), gf.mul(0x02, bit.bxor(b0,b3))), 0) + + util.putByte( bit.bxor(bit.bxor(b2,w), gf.mul(0x02, t )), 1) + + util.putByte( bit.bxor(bit.bxor(b1,v), gf.mul(0x02, bit.bxor(b0,b3))), 2) + + util.putByte( bit.bxor(bit.bxor(b0,w), gf.mul(0x02, u )), 3); +end + +-- +-- generate key schedule for aes decryption +-- +-- uses key schedule for aes encryption and transforms each +-- key by inverse mix column. +-- +function public.expandDecryptionKey(key) + local keySchedule = public.expandEncryptionKey(key); + if (keySchedule == nil) then + return nil; + end + + keySchedule[public.KEY_TYPE] = public.DECRYPTION_KEY; + + for i = 4, (keySchedule[public.ROUNDS] + 1)*4 - 5 do + keySchedule[i] = private.invMixColumnOld(keySchedule[i]); + end + + return keySchedule; +end + +-- +-- xor round key to state +-- +function private.addRoundKey(state, key, round) + for i = 0, 3 do + state[i] = bit.bxor(state[i], key[round*4+i]); + end +end + +-- +-- do encryption round (ShiftRow, SubBytes, MixColumn together) +-- +function private.doRound(origState, dstState) + dstState[0] = bit.bxor(bit.bxor(bit.bxor( + private.table0[util.getByte(origState[0],3)], + private.table1[util.getByte(origState[1],2)]), + private.table2[util.getByte(origState[2],1)]), + private.table3[util.getByte(origState[3],0)]); + + dstState[1] = bit.bxor(bit.bxor(bit.bxor( + private.table0[util.getByte(origState[1],3)], + private.table1[util.getByte(origState[2],2)]), + private.table2[util.getByte(origState[3],1)]), + private.table3[util.getByte(origState[0],0)]); + + dstState[2] = bit.bxor(bit.bxor(bit.bxor( + private.table0[util.getByte(origState[2],3)], + private.table1[util.getByte(origState[3],2)]), + private.table2[util.getByte(origState[0],1)]), + private.table3[util.getByte(origState[1],0)]); + + dstState[3] = bit.bxor(bit.bxor(bit.bxor( + private.table0[util.getByte(origState[3],3)], + private.table1[util.getByte(origState[0],2)]), + private.table2[util.getByte(origState[1],1)]), + private.table3[util.getByte(origState[2],0)]); +end + +-- +-- do last encryption round (ShiftRow and SubBytes) +-- +function private.doLastRound(origState, dstState) + dstState[0] = util.putByte(private.SBox[util.getByte(origState[0],3)], 3) + + util.putByte(private.SBox[util.getByte(origState[1],2)], 2) + + util.putByte(private.SBox[util.getByte(origState[2],1)], 1) + + util.putByte(private.SBox[util.getByte(origState[3],0)], 0); + + dstState[1] = util.putByte(private.SBox[util.getByte(origState[1],3)], 3) + + util.putByte(private.SBox[util.getByte(origState[2],2)], 2) + + util.putByte(private.SBox[util.getByte(origState[3],1)], 1) + + util.putByte(private.SBox[util.getByte(origState[0],0)], 0); + + dstState[2] = util.putByte(private.SBox[util.getByte(origState[2],3)], 3) + + util.putByte(private.SBox[util.getByte(origState[3],2)], 2) + + util.putByte(private.SBox[util.getByte(origState[0],1)], 1) + + util.putByte(private.SBox[util.getByte(origState[1],0)], 0); + + dstState[3] = util.putByte(private.SBox[util.getByte(origState[3],3)], 3) + + util.putByte(private.SBox[util.getByte(origState[0],2)], 2) + + util.putByte(private.SBox[util.getByte(origState[1],1)], 1) + + util.putByte(private.SBox[util.getByte(origState[2],0)], 0); +end + +-- +-- do decryption round +-- +function private.doInvRound(origState, dstState) + dstState[0] = bit.bxor(bit.bxor(bit.bxor( + private.tableInv0[util.getByte(origState[0],3)], + private.tableInv1[util.getByte(origState[3],2)]), + private.tableInv2[util.getByte(origState[2],1)]), + private.tableInv3[util.getByte(origState[1],0)]); + + dstState[1] = bit.bxor(bit.bxor(bit.bxor( + private.tableInv0[util.getByte(origState[1],3)], + private.tableInv1[util.getByte(origState[0],2)]), + private.tableInv2[util.getByte(origState[3],1)]), + private.tableInv3[util.getByte(origState[2],0)]); + + dstState[2] = bit.bxor(bit.bxor(bit.bxor( + private.tableInv0[util.getByte(origState[2],3)], + private.tableInv1[util.getByte(origState[1],2)]), + private.tableInv2[util.getByte(origState[0],1)]), + private.tableInv3[util.getByte(origState[3],0)]); + + dstState[3] = bit.bxor(bit.bxor(bit.bxor( + private.tableInv0[util.getByte(origState[3],3)], + private.tableInv1[util.getByte(origState[2],2)]), + private.tableInv2[util.getByte(origState[1],1)]), + private.tableInv3[util.getByte(origState[0],0)]); +end + +-- +-- do last decryption round +-- +function private.doInvLastRound(origState, dstState) + dstState[0] = util.putByte(private.iSBox[util.getByte(origState[0],3)], 3) + + util.putByte(private.iSBox[util.getByte(origState[3],2)], 2) + + util.putByte(private.iSBox[util.getByte(origState[2],1)], 1) + + util.putByte(private.iSBox[util.getByte(origState[1],0)], 0); + + dstState[1] = util.putByte(private.iSBox[util.getByte(origState[1],3)], 3) + + util.putByte(private.iSBox[util.getByte(origState[0],2)], 2) + + util.putByte(private.iSBox[util.getByte(origState[3],1)], 1) + + util.putByte(private.iSBox[util.getByte(origState[2],0)], 0); + + dstState[2] = util.putByte(private.iSBox[util.getByte(origState[2],3)], 3) + + util.putByte(private.iSBox[util.getByte(origState[1],2)], 2) + + util.putByte(private.iSBox[util.getByte(origState[0],1)], 1) + + util.putByte(private.iSBox[util.getByte(origState[3],0)], 0); + + dstState[3] = util.putByte(private.iSBox[util.getByte(origState[3],3)], 3) + + util.putByte(private.iSBox[util.getByte(origState[2],2)], 2) + + util.putByte(private.iSBox[util.getByte(origState[1],1)], 1) + + util.putByte(private.iSBox[util.getByte(origState[0],0)], 0); +end + +-- +-- encrypts 16 Bytes +-- key encryption key schedule +-- input array with input data +-- inputOffset start index for input +-- output array for encrypted data +-- outputOffset start index for output +-- +function public.encrypt(key, input, inputOffset, output, outputOffset) + --default parameters + inputOffset = inputOffset or 1; + output = output or {}; + outputOffset = outputOffset or 1; + + local state = {}; + local tmpState = {}; + + if (key[public.KEY_TYPE] ~= public.ENCRYPTION_KEY) then + error("No encryption key: "..key[public.KEY_TYPE]); + return; + end + + state = util.bytesToInts(input, inputOffset, 4); + private.addRoundKey(state, key, 0); + + local round = 1; + while (round < key[public.ROUNDS] - 1) do + -- do a double round to save temporary assignments + private.doRound(state, tmpState); + private.addRoundKey(tmpState, key, round); + round = round + 1; + + private.doRound(tmpState, state); + private.addRoundKey(state, key, round); + round = round + 1; + end + + private.doRound(state, tmpState); + private.addRoundKey(tmpState, key, round); + round = round +1; + + private.doLastRound(tmpState, state); + private.addRoundKey(state, key, round); + + return util.intsToBytes(state, output, outputOffset); +end + +-- +-- decrypt 16 bytes +-- key decryption key schedule +-- input array with input data +-- inputOffset start index for input +-- output array for decrypted data +-- outputOffset start index for output +--- +function public.decrypt(key, input, inputOffset, output, outputOffset) + -- default arguments + inputOffset = inputOffset or 1; + output = output or {}; + outputOffset = outputOffset or 1; + + local state = {}; + local tmpState = {}; + + if (key[public.KEY_TYPE] ~= public.DECRYPTION_KEY) then + error("No decryption key: "..key[public.KEY_TYPE]); + return; + end + + state = util.bytesToInts(input, inputOffset, 4); + private.addRoundKey(state, key, key[public.ROUNDS]); + + local round = key[public.ROUNDS] - 1; + while (round > 2) do + -- do a double round to save temporary assignments + private.doInvRound(state, tmpState); + private.addRoundKey(tmpState, key, round); + round = round - 1; + + private.doInvRound(tmpState, state); + private.addRoundKey(state, key, round); + round = round - 1; + end + + private.doInvRound(state, tmpState); + private.addRoundKey(tmpState, key, round); + round = round - 1; + + private.doInvLastRound(tmpState, state); + private.addRoundKey(state, key, round); + + return util.intsToBytes(state, output, outputOffset); +end + +-- calculate all tables when loading this file +private.calcSBox(); +private.calcRoundTables(); +private.calcInvRoundTables(); + +return public; diff -r 000000000000 -r 598d09faf89c aeslua/buffer.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/aeslua/buffer.lua Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,27 @@ +local public = {}; + +local aeslua = require("aeslua"); +aeslua.buffer = public; + +function public.new () + return {}; +end + +function public.addString (stack, s) + table.insert(stack, s) + for i = #stack - 1, 1, -1 do + if #stack[i] > #stack[i+1] then + break; + end + stack[i] = stack[i] .. table.remove(stack); + end +end + +function public.toString (stack) + for i = #stack - 1, 1, -1 do + stack[i] = stack[i] .. table.remove(stack); + end + return stack[1]; +end + +return public; diff -r 000000000000 -r 598d09faf89c aeslua/ciphermode.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/aeslua/ciphermode.lua Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,148 @@ +local aes = require("aeslua.aes"); +local util = require("aeslua.util"); +local buffer = require("aeslua.buffer"); + +local public = {}; + +local aeslua = require("aeslua"); +aeslua.ciphermode = public; + +-- +-- Encrypt strings +-- key - byte array with key +-- string - string to encrypt +-- modefunction - function for cipher mode to use +-- +function public.encryptString(key, data, modeFunction) + local iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + local keySched = aes.expandEncryptionKey(key); + local encryptedData = buffer.new(); + + for i = 1, #data/16 do + local offset = (i-1)*16 + 1; + local byteData = {string.byte(data,offset,offset +15)}; + + modeFunction(keySched, byteData, iv); + + buffer.addString(encryptedData, string.char(unpack(byteData))); + end + + return buffer.toString(encryptedData); +end + +-- +-- the following 4 functions can be used as +-- modefunction for encryptString +-- + +-- Electronic code book mode encrypt function +function public.encryptECB(keySched, byteData, iv) + aes.encrypt(keySched, byteData, 1, byteData, 1); +end + +-- Cipher block chaining mode encrypt function +function public.encryptCBC(keySched, byteData, iv) + util.xorIV(byteData, iv); + + aes.encrypt(keySched, byteData, 1, byteData, 1); + + for j = 1,16 do + iv[j] = byteData[j]; + end +end + +-- Output feedback mode encrypt function +function public.encryptOFB(keySched, byteData, iv) + aes.encrypt(keySched, iv, 1, iv, 1); + util.xorIV(byteData, iv); +end + +-- Cipher feedback mode encrypt function +function public.encryptCFB(keySched, byteData, iv) + aes.encrypt(keySched, iv, 1, iv, 1); + util.xorIV(byteData, iv); + + for j = 1,16 do + iv[j] = byteData[j]; + end +end + +-- +-- Decrypt strings +-- key - byte array with key +-- string - string to decrypt +-- modefunction - function for cipher mode to use +-- +function public.decryptString(key, data, modeFunction) + local iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + local keySched; + if (modeFunction == public.decryptOFB or modeFunction == public.decryptCFB) then + keySched = aes.expandEncryptionKey(key); + else + keySched = aes.expandDecryptionKey(key); + end + + local decryptedData = buffer.new(); + + for i = 1, #data/16 do + local offset = (i-1)*16 + 1; + local byteData = {string.byte(data,offset,offset +15)}; + + iv = modeFunction(keySched, byteData, iv); + + buffer.addString(decryptedData, string.char(unpack(byteData))); + end + + return buffer.toString(decryptedData); +end + +-- +-- the following 4 functions can be used as +-- modefunction for decryptString +-- + +-- Electronic code book mode decrypt function +function public.decryptECB(keySched, byteData, iv) + + aes.decrypt(keySched, byteData, 1, byteData, 1); + + return iv; +end + +-- Cipher block chaining mode decrypt function +function public.decryptCBC(keySched, byteData, iv) + local nextIV = {}; + for j = 1,16 do + nextIV[j] = byteData[j]; + end + + aes.decrypt(keySched, byteData, 1, byteData, 1); + util.xorIV(byteData, iv); + + return nextIV; +end + +-- Output feedback mode decrypt function +function public.decryptOFB(keySched, byteData, iv) + aes.encrypt(keySched, iv, 1, iv, 1); + util.xorIV(byteData, iv); + + return iv; +end + +-- Cipher feedback mode decrypt function +function public.decryptCFB(keySched, byteData, iv) + local nextIV = {}; + for j = 1,16 do + nextIV[j] = byteData[j]; + end + + aes.encrypt(keySched, iv, 1, iv, 1); + + util.xorIV(byteData, iv); + + return nextIV; +end + +return public; diff -r 000000000000 -r 598d09faf89c aeslua/gf.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/aeslua/gf.lua Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,117 @@ +local bit = require("bit"); + +-- finite field with base 2 and modulo irreducible polynom x^8+x^4+x^3+x+1 = 0x11d +local private = {}; +local public = {}; + +local aeslua = require("aeslua"); +aeslua.gf = public; + +-- private data of gf +private.n = 0x100; +private.ord = 0xff; +private.irrPolynom = 0x11b; +private.exp = {}; +private.log = {}; + +-- +-- add two polynoms (its simply xor) +-- +function public.add(operand1, operand2) + return bit.bxor(operand1,operand2); +end + +-- +-- subtract two polynoms (same as addition) +-- +function public.sub(operand1, operand2) + return bit.bxor(operand1,operand2); +end + +-- +-- inverts element +-- a^(-1) = g^(order - log(a)) +-- +function public.invert(operand) + -- special case for 1 + if (operand == 1) then + return 1; + end; + -- normal invert + local exponent = private.ord - private.log[operand]; + return private.exp[exponent]; +end + +-- +-- multiply two elements using a logarithm table +-- a*b = g^(log(a)+log(b)) +-- +function public.mul(operand1, operand2) + if (operand1 == 0 or operand2 == 0) then + return 0; + end + + local exponent = private.log[operand1] + private.log[operand2]; + if (exponent >= private.ord) then + exponent = exponent - private.ord; + end + return private.exp[exponent]; +end + +-- +-- divide two elements +-- a/b = g^(log(a)-log(b)) +-- +function public.div(operand1, operand2) + if (operand1 == 0) then + return 0; + end + -- TODO: exception if operand2 == 0 + local exponent = private.log[operand1] - private.log[operand2]; + if (exponent < 0) then + exponent = exponent + private.ord; + end + return private.exp[exponent]; +end + +-- +-- print logarithmic table +-- +function public.printLog() + for i = 1, private.n do + print("log(", i-1, ")=", private.log[i-1]); + end +end + +-- +-- print exponentiation table +-- +function public.printExp() + for i = 1, private.n do + print("exp(", i-1, ")=", private.exp[i-1]); + end +end + +-- +-- calculate logarithmic and exponentiation table +-- +function private.initMulTable() + local a = 1; + + for i = 0,private.ord-1 do + private.exp[i] = a; + private.log[a] = i; + + -- multiply with generator x+1 -> left shift + 1 + a = bit.bxor(bit.lshift(a, 1), a); + + -- if a gets larger than order, reduce modulo irreducible polynom + if a > private.ord then + a = public.sub(a, private.irrPolynom); + end + end +end + +private.initMulTable(); + +return public; diff -r 000000000000 -r 598d09faf89c aeslua/init.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/aeslua/init.lua Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,3 @@ +local aeslua = {}; +package.loaded.aeslua = aeslua; +return aeslua; diff -r 000000000000 -r 598d09faf89c aeslua/util.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/aeslua/util.lua Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,155 @@ +local bit = require("bit"); + +local public = {}; +local private = {}; + +local aeslua = require("aeslua"); +aeslua.util = public; + +-- +-- calculate the parity of one byte +-- +function public.byteParity(byte) + byte = bit.bxor(byte, bit.rshift(byte, 4)); + byte = bit.bxor(byte, bit.rshift(byte, 2)); + byte = bit.bxor(byte, bit.rshift(byte, 1)); + return bit.band(byte, 1); +end + +-- +-- get byte at position index +-- +function public.getByte(number, index) + if (index == 0) then + return bit.band(number,0xff); + else + return bit.band(bit.rshift(number, index*8),0xff); + end +end + + +-- +-- put number into int at position index +-- +function public.putByte(number, index) + if (index == 0) then + return bit.band(number,0xff); + else + return bit.lshift(bit.band(number,0xff),index*8); + end +end + +-- +-- convert byte array to int array +-- +function public.bytesToInts(bytes, start, n) + local ints = {}; + for i = 0, n - 1 do + ints[i] = public.putByte(bytes[start + (i*4) ], 3) + + public.putByte(bytes[start + (i*4) + 1], 2) + + public.putByte(bytes[start + (i*4) + 2], 1) + + public.putByte(bytes[start + (i*4) + 3], 0); + end + return ints; +end + +-- +-- convert int array to byte array +-- +function public.intsToBytes(ints, output, outputOffset, n) + n = n or #ints; + for i = 0, n do + for j = 0,3 do + output[outputOffset + i*4 + (3 - j)] = public.getByte(ints[i], j); + end + end + return output; +end + +-- +-- convert bytes to hexString +-- +function private.bytesToHex(bytes) + local hexBytes = ""; + + for i,byte in ipairs(bytes) do + hexBytes = hexBytes .. string.format("%02x ", byte); + end + + return hexBytes; +end + +-- +-- convert data to hex string +-- +function public.toHexString(data) + local type = type(data); + if (type == "number") then + return string.format("%08x",data); + elseif (type == "table") then + return private.bytesToHex(data); + elseif (type == "string") then + local bytes = {string.byte(data, 1, #data)}; + + return private.bytesToHex(bytes); + else + return data; + end +end + +function public.padByteString(data) + local dataLength = #data; + + local random1 = math.random(0,255); + local random2 = math.random(0,255); + + local prefix = string.char(random1, + random2, + random1, + random2, + public.getByte(dataLength, 3), + public.getByte(dataLength, 2), + public.getByte(dataLength, 1), + public.getByte(dataLength, 0)); + + data = prefix .. data; + + local paddingLength = math.ceil(#data/16)*16 - #data; + local padding = ""; + for i=1,paddingLength do + padding = padding .. string.char(math.random(0,255)); + end + + return data .. padding; +end + +function private.properlyDecrypted(data) + local random = {string.byte(data,1,4)}; + + if (random[1] == random[3] and random[2] == random[4]) then + return true; + end + + return false; +end + +function public.unpadByteString(data) + if (not private.properlyDecrypted(data)) then + return nil; + end + + local dataLength = public.putByte(string.byte(data,5), 3) + + public.putByte(string.byte(data,6), 2) + + public.putByte(string.byte(data,7), 1) + + public.putByte(string.byte(data,8), 0); + + return string.sub(data,9,8+dataLength); +end + +function public.xorIV(data, iv) + for i = 1,16 do + data[i] = bit.bxor(data[i], iv[i]); + end +end + +return public; diff -r 000000000000 -r 598d09faf89c crc16/crc16.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc16/crc16.lua Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,33 @@ +local bit = require "bit"; + +module "crc16" + +function hash(str) + local crc; + + local function initCrc() + crc = 0xffff; + end + + local function updCrc(byte) + crc = bit.bxor(crc, byte); + for i=1,8 do + local j = bit.band(crc, 1); + crc = bit.rshift(crc, 1); + if j ~= 0 then + crc = bit.bxor(crc, 0x8408); + end + end + end + + local function getCrc(str) + initCrc(); + for i = 1, #str do + updCrc(str:byte(i)); + end + return crc; + end + return getCrc(str); +end + +return { hash = hash } diff -r 000000000000 -r 598d09faf89c squishy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/squishy Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,12 @@ +Module "aeslua" "aeslua/init.lua" +Module "aeslua.ciphermode" "aeslua/ciphermode.lua" +Module "aeslua.aes" "aeslua/aes.lua" +Module "aeslua.util" "aeslua/util.lua" +Module "aeslua.buffer" "aeslua/buffer.lua" +Module "aeslua.gf" "aeslua/gf.lua" + +Module "crc16" "crc16/crc16.lua" + +Main "yubikey/init.lua" + +Output "yubikey.lua" diff -r 000000000000 -r 598d09faf89c yubikey/init.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yubikey/init.lua Wed Feb 16 20:29:33 2011 +0000 @@ -0,0 +1,124 @@ +local _M = {}; + +local aeslua = require "aeslua"; +local ciphermode = require "aeslua.ciphermode"; +local crc16 = require "crc16"; + +local modhex2hex; +do + local modhex_map = {}; + local modhex_chars = "cbdefghijklnrtuv"; + for i=1,16 do + modhex_map[modhex_chars:sub(i,i)] = ("%x"):format(i-1); + end + function modhex2hex(modhex) + if modhex then + return (modhex:gsub(".", modhex_map)); + end + end +end +_M.modhex2hex = modhex2hex; + +local function hex2bin(hex) + if hex then + return (hex:gsub("..", function (c) return string.char(tonumber(c, 16)); end)); + end +end +_M.hex2bin = hex2bin; + +local function bin2hex(bin) + if bin then + return (bin:gsub(".", function (b) return ("%02x"):format(b:byte()); end)); + end +end +_M.bin2hex = bin2hex; + +local otp_parser = {}; +local otp_parser_mt = { __index = otp_parser }; + +function _M.new_fetch_key_hex(fetchkeyhex) + return function (...) return hex2bin(fetchkeyhex(...)); end +end + +function _M.new_otp_parser(config) + return setmetatable({ + config = config, + }, otp_parser_mt); +end + +function otp_parser:parse(otp, key) + -- Password is any extra data before the real OTP + local password; + if #otp > 32 + self.config.prefix_length then + password = otp:sub(1, #otp - (32 + self.config.prefix_length)); + otp = otp:sub(#password+1); + end + local prefix = otp:sub(1, self.config.prefix_length); + local token = otp:sub(#prefix+1); + if not key then + key = self.config.fetch_key(prefix); + else + key = hex2bin(key); + end + if not key then return false, "no-key"; end + key = {key:byte(1,#key)} + local decrypted = ciphermode.decryptString(key, hex2bin(modhex2hex(token)), ciphermode.decryptCBC); + if not decrypted then return false, "decrypt-failed"; end + -- Extract private UID + local uid = decrypted:sub(1,6); + -- Build insertion counter (2 bytes) + local use1, use2 = decrypted:sub(7,8):byte(1,2); + local use_ctr = use1 + math.pow(2, 8)*use2; + -- Build timestamp (3 bytes) + local time1, time2, time3 = decrypted:sub(9,11):byte(1,3); + local timestamp = time1 + math.pow(2,8)*time2 + math.pow(2, 16)*time3; + -- Extract session counter (1 byte) + local session_ctr = decrypted:sub(12, 12):byte(); + + if crc16.hash(decrypted) ~= 0xf0b8 then + return false, "invalid-checksum"; + end + + -- Return parsed fields + return true, { + password = password; + public_id = prefix; + token = token; + private_id = bin2hex(uid); + session_counter = session_ctr; + use_counter = use_ctr; + timestamp = timestamp; + }; +end + +function _M.new_authenticator(config) + local parser = _M.new_otp_parser(config); + local function authenticate(self, otp, key, device_info, userdata) + -- Parse OTP, get device data (from config callback) + local ok, ret = parser:parse(otp, key); + if not ok then return ok, ret; end + + if not device_info then + device_info = config.fetch_device_info(ret); + end + + if ret.use_counter < (device_info.use_counter or 0) + or ((ret.use_counter == (device_info.use_counter or 0)) + and (ret.session_counter <= (device_info.session_counter or 0))) then + return false, "otp-already-used"; + end + + local authed, err = config.check_credentials(ret, device_info, userdata); + if not authed then return authed, err; end + + device_info.use_counter = ret.use_counter; + device_info.session_counter = ret.session_counter; + + config.store_device_info(device_info, userdata); + + return true, ret; + end + return { authenticate = authenticate }; +end + +return _M;