├── var ├── name ├── title ├── created ├── version ├── organization ├── summary ├── description ├── authors ├── requirements ├── copyrights └── resources ├── Gemfile ├── .gitignore ├── .yardopts ├── .travis.yml ├── MANIFEST ├── demo ├── applique │ └── setup.rb └── 01_example.rdoc ├── work └── rubyforge.syckle ├── Assembly ├── HISTORY.rdoc ├── .ruby ├── README.rdoc ├── LICENSE.txt ├── COPYING.rdoc ├── .gemspec └── lib └── bicrypt.rb /var/name: -------------------------------------------------------------------------------- 1 | bicrypt -------------------------------------------------------------------------------- /var/title: -------------------------------------------------------------------------------- 1 | BiCrypt -------------------------------------------------------------------------------- /var/created: -------------------------------------------------------------------------------- 1 | 2007-07-01 -------------------------------------------------------------------------------- /var/version: -------------------------------------------------------------------------------- 1 | 1.2.0 2 | -------------------------------------------------------------------------------- /var/organization: -------------------------------------------------------------------------------- 1 | Rubyworks -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | gemspec 3 | -------------------------------------------------------------------------------- /var/summary: -------------------------------------------------------------------------------- 1 | Two-Way Encyrption/Decryption -------------------------------------------------------------------------------- /var/description: -------------------------------------------------------------------------------- 1 | Simple two-way encryption/decryption class. -------------------------------------------------------------------------------- /var/authors: -------------------------------------------------------------------------------- 1 | --- 2 | - Thomas Sawyer 3 | -------------------------------------------------------------------------------- /var/requirements: -------------------------------------------------------------------------------- 1 | --- 2 | - detroit (build) 3 | - qed (test) 4 | -------------------------------------------------------------------------------- /var/copyrights: -------------------------------------------------------------------------------- 1 | --- 2 | - Copyright (c) 2007 Thomas Sawyer (BSD-2-Clause) 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .fire/digest 2 | .yardoc 3 | doc 4 | log 5 | pkg 6 | tmp 7 | web 8 | DEMO.rdoc 9 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --title BiCrypt 2 | --readme README.rdoc 3 | --private 4 | --protected 5 | lib 6 | - 7 | [A-Z]*.* 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | script: "bundle exec qed" 3 | rvm: 4 | - 1.8.7 5 | - 1.9.2 6 | - 1.9.3 7 | - rbx-2.0 8 | - jruby 9 | - ree 10 | 11 | -------------------------------------------------------------------------------- /var/resources: -------------------------------------------------------------------------------- 1 | --- 2 | home: http://rubyworks.github.com/bicrypt 3 | code: http://github.com/rubyworks/bicrypt 4 | mail: http://groups.google.com/groups/rubyworks-mailinglist 5 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | #!mast .ruby .yardopts bin lib spec test [A-Z]*.* 2 | .ruby 3 | .yardopts 4 | lib/bicrypt.rb 5 | HISTORY.rdoc 6 | LICENSE.txt 7 | README.rdoc 8 | QED.rdoc 9 | COPYING.rdoc 10 | -------------------------------------------------------------------------------- /demo/applique/setup.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | require 'stringio' 3 | 4 | Before :demo do 5 | if File.exist?('tmp') 6 | FileUtils.rm_r('tmp') 7 | end 8 | FileUtils.mkdir('tmp') 9 | end 10 | 11 | -------------------------------------------------------------------------------- /work/rubyforge.syckle: -------------------------------------------------------------------------------- 1 | --- 2 | rubyforge: 3 | service : Rubyforge 4 | unixname: ~ 5 | groupid : ~ 6 | package : <%= package %> 7 | sitemap: 8 | doc/rdoc: <%= package %> 9 | active : false 10 | 11 | -------------------------------------------------------------------------------- /Assembly: -------------------------------------------------------------------------------- 1 | --- 2 | github: 3 | gh_pages: web 4 | 5 | gem: 6 | active: true 7 | 8 | dnote: 9 | title: Developer's Notes 10 | output: log/NOTES.rdoc 11 | labels: ~ 12 | 13 | yard: 14 | yardopts: true 15 | priority: 2 16 | 17 | qed: 18 | files: demo 19 | active: true 20 | 21 | qedoc: 22 | files: demo 23 | output: DEMO.rdoc 24 | 25 | readme: 26 | service: custom 27 | document: | 28 | cmd = 'malt README.rdoc > web/readme.html' 29 | puts cmd; sh cmd 30 | 31 | vclog: 32 | output: 33 | - log/ChangeLog.rdoc 34 | 35 | email: 36 | mailto: 37 | - ruby-talk@ruby-lang.org 38 | - rubyworks-mailinglist@googlegroups.com 39 | 40 | -------------------------------------------------------------------------------- /HISTORY.rdoc: -------------------------------------------------------------------------------- 1 | = RELEASE HISTORY 2 | 3 | == 1.2.0 / 2011-10-25 4 | 5 | This is another maintenance release to bring the build configuration 6 | up to date with modern tools. Function-wise nothing has changed. 7 | The major verison was bumped only to mark a fresh base. 8 | 9 | Changes: 10 | 11 | * Modernize build configuration. 12 | 13 | 14 | == 1.1.1 / 2011-05-15 15 | 16 | This release simply fixes a build dependency. 17 | 18 | Changes: 19 | 20 | * Syckle has been renamed to Redline. 21 | 22 | 23 | == 1.1.0 / 2010-10-26 24 | 25 | This release makes one simple change. It removed the String#^ 26 | extension and replaces it with BiCrypt#xor, thus preventing 27 | any potential core extension clashes. 28 | 29 | Changes: 30 | 31 | * Replace String#^ with ByCrypt#xor. 32 | 33 | 34 | == 1.0.0 / 2009-07-01 35 | 36 | Initial stand-alone release, ported from Ruby Facets. 37 | 38 | Changes: 39 | 40 | * Happy Birthday! 41 | 42 | -------------------------------------------------------------------------------- /.ruby: -------------------------------------------------------------------------------- 1 | --- 2 | source: 3 | - var 4 | authors: 5 | - name: Thomas Sawyer 6 | email: transfire@gmail.com 7 | copyrights: 8 | - holder: Thomas Sawyer 9 | year: '2007' 10 | license: BSD-2-Clause 11 | replacements: [] 12 | alternatives: [] 13 | requirements: 14 | - name: detroit 15 | groups: 16 | - build 17 | development: true 18 | - name: qed 19 | groups: 20 | - test 21 | development: true 22 | dependencies: [] 23 | conflicts: [] 24 | repositories: [] 25 | resources: 26 | home: http://rubyworks.github.com/bicrypt 27 | code: http://github.com/rubyworks/bicrypt 28 | mail: http://groups.google.com/groups/rubyworks-mailinglist 29 | extra: {} 30 | load_path: 31 | - lib 32 | revision: 0 33 | created: '2007-07-01' 34 | summary: Two-Way Encyrption/Decryption 35 | title: BiCrypt 36 | version: 1.2.0 37 | name: bicrypt 38 | description: Simple two-way encryption/decryption class. 39 | organization: Rubyworks 40 | date: '2011-11-11' 41 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = BiCrypt 2 | 3 | {Website}[http://rubyworks.github.com/bicrypt] | 4 | {Documentation}[http://rubydoc.info/gems/bicrypt] | 5 | {Development}[http://github.com/rubyworks/bicrypt] 6 | 7 | {}[http://travis-ci.org/rubyworks/bicrypt] 8 | 9 | 10 | == DESCRIPTION 11 | 12 | BiCrypt is a simple two-way encryption class. 13 | 14 | 15 | == FEATURES 16 | 17 | * Very easy to use. 18 | * Good for light-weight "deterrence" applications. 19 | 20 | 21 | == RELEASE NOTES 22 | 23 | Please see HISTORY.rdoc file. 24 | 25 | 26 | == USAGE 27 | 28 | See QED.rdoc or qed/01_example.rdoc for the run down. 29 | 30 | 31 | == HOW TO INSTALL 32 | 33 | To install with RubyGems simply open a console and type: 34 | 35 | $ gem install bicrypt 36 | 37 | Local installation requires Setup.rb (gem install setup), 38 | then download the tarball package and type: 39 | 40 | $ tar -xvzf bicrypt-1.0.0.tgz 41 | $ cd bicrypt-1.0.0 42 | $ sudo setup.rb all 43 | 44 | Windows users use 'ruby setup.rb all'. 45 | 46 | 47 | == COPYRIGHT 48 | 49 | Copyright (c) 2007 Rubyworks. All rights reserved. 50 | 51 | BiCrypt is distibuted under the terms of the *BSD-2-Clause* license. 52 | 53 | See COPYING.rdoc for details. 54 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2007 Thomas Sawyer. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 14 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 15 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 16 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 17 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 18 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 19 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 20 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | 23 | -------------------------------------------------------------------------------- /demo/01_example.rdoc: -------------------------------------------------------------------------------- 1 | = BiCrypt 2 | 3 | require 'bicrypt' 4 | 5 | Encrypt string. 6 | 7 | e = BiCrypt.new("akey") 8 | 9 | m = e.encrypt_string("This is a message!") 10 | 11 | m.assert! == "This is a message!" 12 | 13 | Decrypt string. 14 | 15 | d = BiCrypt.new("akey") 16 | 17 | r = d.decrypt_string(m) 18 | 19 | r.assert == "This is a message!" 20 | 21 | Encrypt file. 22 | 23 | File.open('EXAMPLE.txt', 'w'){ |f| f << "This is an example." } 24 | 25 | e = BiCrypt.new("akey") 26 | 27 | e.encrypt_file('EXAMPLE.txt', 'secret.txt') 28 | 29 | File.read('EXAMPLE.txt').assert! == File.read('secret.txt') 30 | 31 | Decrypt file. 32 | 33 | d = BiCrypt.new("akey") 34 | 35 | d.decrypt_file('secret.txt', 'tmp/README.rdoc') 36 | 37 | File.read('EXAMPLE.txt').assert == File.read('EXAMPLE.txt') 38 | 39 | Both the string and the file methods are built on top of the general 40 | stream methods. 41 | 42 | plainIO = StringIO.new("This is the message!") 43 | cryptIO = StringIO.new('') 44 | 45 | e = BiCrypt.new("akey") 46 | 47 | e.encrypt_stream(plainIO, cryptIO) 48 | 49 | Decrypt IO stream. 50 | 51 | crypt2IO = StringIO.new(cryptIO.string) 52 | resultIO = StringIO.new('') 53 | 54 | d = BiCrypt.new("akey") 55 | 56 | d.decrypt_stream(crypt2IO, resultIO) 57 | 58 | resultIO.string.assert == "This is the message!" 59 | 60 | -------------------------------------------------------------------------------- /COPYING.rdoc: -------------------------------------------------------------------------------- 1 | = COPYRIGHT NOTICES 2 | 3 | == BiCrypt 4 | 5 | Copyright:: (c) 2007 Rubyworks 6 | License:: BSD-2-Clause 7 | Website:: http://rubyworks.github.com/bicrypt 8 | 9 | Copyright (c) 2007 Rubyworks. All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | 1. Redistributions of source code must retain the above copyright notice, 15 | this list of conditions and the following disclaimer. 16 | 17 | 2. Redistributions in binary form must reproduce the above copyright 18 | notice, this list of conditions and the following disclaimer in the 19 | documentation and/or other materials provided with the distribution. 20 | 21 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 22 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 23 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 28 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 30 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /.gemspec: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'yaml' 4 | 5 | metadata = YAML.load_file('.ruby') 6 | 7 | manifest = Dir.glob('manifest{,.txt}', File::FNM_CASEFOLD).first 8 | 9 | 10 | Gem::Specification.new do |gemspec| 11 | 12 | scm = case 13 | when File.directory?('.git') 14 | :git 15 | end 16 | 17 | files = case 18 | when manifest 19 | File.readlines(manifest). 20 | map{ |line| line.strip }. 21 | reject{ |line| line.empty? || line[0,1] == '#' } 22 | when scm == :git 23 | `git ls-files -z`.split("\0") 24 | else 25 | Dir.glob('{**/}{.*,*}') # TODO: be more specific using standard locations ? 26 | end.select{ |path| File.file?(path) } 27 | 28 | patterns = { 29 | :bin_files => 'bin/*', 30 | :lib_files => 'lib/{**/}*.rb', 31 | :ext_files => 'ext/{**/}extconf.rb', 32 | :doc_files => '*.{txt,rdoc,md,markdown,tt,textile}', 33 | :test_files => '{test/{**/}*_test.rb,spec/{**/}*_spec.rb}' 34 | } 35 | 36 | glob_files = lambda { |pattern| 37 | Dir.glob(pattern).select { |path| 38 | File.file?(path) && files.include?(path) 39 | } 40 | } 41 | 42 | #files = glob_files[patterns[:files]] 43 | 44 | executables = glob_files[patterns[:bin_files]].map do |path| 45 | File.basename(path) 46 | end 47 | 48 | extensions = glob_files[patterns[:ext_files]].map do |path| 49 | File.basename(path) 50 | end 51 | 52 | # build-out the gemspec 53 | 54 | case metadata['revision'] 55 | when 0 56 | gemspec.name = metadata['name'] 57 | gemspec.version = metadata['version'] 58 | gemspec.summary = metadata['summary'] 59 | gemspec.description = metadata['description'] 60 | 61 | metadata['authors'].each do |author| 62 | gemspec.authors << author['name'] 63 | 64 | if author.has_key?('email') 65 | if gemspec.email 66 | gemspec.email << author['email'] 67 | else 68 | gemspec.email = [author['email']] 69 | end 70 | end 71 | end 72 | 73 | gemspec.licenses = metadata['copyrights'].map{ |c| c['license'] }.compact 74 | 75 | metadata['requirements'].each do |req| 76 | name = req['name'] 77 | version = req['version'] 78 | groups = req['groups'] || [] 79 | 80 | case version 81 | when /^(.*?)\+$/ 82 | version = ">= #{$1}" 83 | when /^(.*?)\-$/ 84 | version = "< #{$1}" 85 | when /^(.*?)\~$/ 86 | version = "~> #{$1}" 87 | end 88 | 89 | if groups.empty? or groups.include?('runtime') 90 | # populate runtime dependencies 91 | if gemspec.respond_to?(:add_runtime_dependency) 92 | gemspec.add_runtime_dependency(name,*version) 93 | else 94 | gemspec.add_dependency(name,*version) 95 | end 96 | else 97 | # populate development dependencies 98 | if gemspec.respond_to?(:add_development_dependency) 99 | gemspec.add_development_dependency(name,*version) 100 | else 101 | gemspec.add_dependency(name,*version) 102 | end 103 | end 104 | end 105 | 106 | # convert external dependencies into a requirements 107 | if metadata['external_dependencies'] 108 | ##gemspec.requirements = [] unless metadata['external_dependencies'].empty? 109 | metadata['external_dependencies'].each do |req| 110 | gemspec.requirements << req.to_s 111 | end 112 | end 113 | 114 | # determine homepage from resources 115 | homepage = metadata['resources'].find{ |key, url| key =~ /^home/ } 116 | gemspec.homepage = homepage.last if homepage 117 | 118 | gemspec.require_paths = metadata['load_path'] || ['lib'] 119 | gemspec.post_install_message = metadata['install_message'] 120 | 121 | # RubyGems specific metadata 122 | gemspec.files = files 123 | gemspec.extensions = extensions 124 | gemspec.executables = executables 125 | 126 | if Gem::VERSION < '1.7.' 127 | gemspec.default_executable = gemspec.executables.first 128 | end 129 | 130 | gemspec.test_files = glob_files[patterns[:test_files]] 131 | 132 | unless gemspec.files.include?('.document') 133 | gemspec.extra_rdoc_files = glob_files[patterns[:doc_files]] 134 | end 135 | end 136 | end 137 | -------------------------------------------------------------------------------- /lib/bicrypt.rb: -------------------------------------------------------------------------------- 1 | # BiCrypt - A Simple Two-Way Encryption Class 2 | 3 | require 'stringio' 4 | 5 | # = BiCrypt 6 | # 7 | # A simple two-way encryption class. 8 | # 9 | # This class is based on algorithms given in Applied Cryptography 2nd Ed. 10 | # 11 | # If subclassed, the new encryption class must provide three methods: 12 | # 13 | # * encrypt_block(block) 14 | # * decrypt_block(block) 15 | # * block_size() 16 | # 17 | class BiCrypt 18 | 19 | # Current release version of BiCrypt. 20 | VERSION = '1.2.0' 21 | 22 | # 23 | ULONG = 0x100000000 24 | 25 | # These are the S-boxes given in Applied Cryptography 2nd Ed., p. 333 26 | SBOX = [ 27 | [4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3], 28 | [14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9], 29 | [5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11], 30 | [7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3], 31 | [6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2], 32 | [4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14], 33 | [13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12], 34 | [1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12] 35 | ] 36 | 37 | # These are the S-boxes given in the GOST source code listing in Applied 38 | # Cryptography 2nd Ed., p. 644. They appear to be from the DES S-boxes 39 | # [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 ], 40 | # [ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 ], 41 | # [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 ], 42 | # [ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 ], 43 | # [ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 ], 44 | # [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 ], 45 | # [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 ], 46 | # [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 ] 47 | 48 | # Setup if BiCrypt instance. 49 | # 50 | # @param [String] User key. 51 | def initialize(userKey) 52 | @sBox = SBOX 53 | 54 | if userKey.size < 8 55 | userKey += '01234567' 56 | end 57 | 58 | #@sTable = precalculate_s_table() 59 | 60 | # derive the 32-byte key from the user-supplied key 61 | userKeyLength = userKey.length 62 | 63 | @key = userKey[0..31].unpack('C'*32) 64 | 65 | if (userKeyLength < 32) 66 | userKeyLength.upto(31) { @key << 0 } 67 | end 68 | end 69 | 70 | public 71 | 72 | # Encrypt an IO stream. 73 | def encrypt_stream(plainStream, cryptStream) 74 | # Cypher-block-chain mode 75 | 76 | initVector = generate_initialization_vector(block_size() / 4) 77 | chain = encrypt_block(initVector) 78 | cryptStream.write(chain) 79 | 80 | while ((block = plainStream.read(block_size())) && (block.length == block_size())) 81 | block = xor(block, chain) 82 | encrypted = encrypt_block(block) 83 | cryptStream.write(encrypted) 84 | chain = encrypted 85 | end 86 | 87 | # write the final block 88 | # At most block_size()-1 bytes can be part of the message. 89 | # That means the final byte can be used to store the number of meaningful 90 | # bytes in the final block 91 | block = '' if block.nil? 92 | buffer = block.split('') 93 | remainingMessageBytes = buffer.length 94 | # we use 7-bit characters to avoid possible strange behavior on the Mac 95 | remainingMessageBytes.upto(block_size()-2) { buffer << rand(128).chr } 96 | buffer << remainingMessageBytes.chr 97 | block = buffer.join('') 98 | block = xor(block, chain) 99 | encrypted = encrypt_block(block) 100 | cryptStream.write(encrypted) 101 | end 102 | 103 | # Decrypt an encrypted IO stream. 104 | def decrypt_stream(cryptStream, plainStream) 105 | # Cypher-block-chain mode 106 | chain = cryptStream.read(block_size()) 107 | 108 | while (block = cryptStream.read(block_size())) 109 | decrypted = decrypt_block(block) 110 | plainText = xor(decrypted, chain) 111 | plainStream.write(plainText) unless cryptStream.eof? 112 | chain = block 113 | end 114 | 115 | # write the final block, omitting the padding 116 | buffer = plainText.split('') 117 | remainingMessageBytes = buffer.last.unpack('C').first 118 | remainingMessageBytes.times { plainStream.write(buffer.shift) } 119 | end 120 | 121 | # Encrypt a file. 122 | def encrypt_file(plainFilename, cryptFilename) 123 | plainFile = carefully_open_file(plainFilename, 'rb') 124 | cryptFile = carefully_open_file(cryptFilename, 'wb+') 125 | encrypt_stream(plainFile, cryptFile) 126 | plainFile.close unless plainFile.closed? 127 | cryptFile.close unless cryptFile.closed? 128 | end 129 | 130 | # Decrypt an encrypted file. 131 | def decrypt_file(cryptFilename, plainFilename) 132 | cryptFile = carefully_open_file(cryptFilename, 'rb') 133 | plainFile = carefully_open_file(plainFilename, 'wb+') 134 | decrypt_stream(cryptFile, plainFile) 135 | cryptFile.close unless cryptFile.closed? 136 | plainFile.close unless plainFile.closed? 137 | end 138 | 139 | # Encrypt a string. 140 | def encrypt_string(plainText) 141 | plainStream = StringIO.new(plainText) 142 | cryptStream = StringIO.new('') 143 | encrypt_stream(plainStream, cryptStream) 144 | cryptText = cryptStream.string 145 | return(cryptText) 146 | end 147 | 148 | # Decrypt an encrypted string. 149 | def decrypt_string(cryptText) 150 | cryptStream = StringIO.new(cryptText) 151 | plainStream = StringIO.new('') 152 | decrypt_stream(cryptStream, plainStream) 153 | plainText = plainStream.string 154 | return(plainText) 155 | end 156 | 157 | private 158 | 159 | # S-boxes. 160 | attr :sBox 161 | 162 | # Calculated S-boxes 163 | def sTable 164 | @sTable ||= ( 165 | sTable = [[], [], [], []] 166 | 0.upto(3) { |i| 167 | 0.upto(255) { |j| 168 | t = sBox[2*i][j % 16] | (sBox[2*i+1][j/16] << 4) 169 | u = (8*i + 11) % 32 170 | v = (t << u) | (t >> (32-u)) 171 | sTable[i][j] = (v % ULONG) 172 | } 173 | } 174 | sTable 175 | ) 176 | end 177 | 178 | # Encrypt a block. 179 | def encrypt_block(block) 180 | xl, xr = block.unpack('NN') 181 | xl, xr = encrypt_pair(xl, xr) 182 | encrypted = [xl, xr].pack('NN') 183 | return(encrypted) 184 | end 185 | 186 | # Decrypt a block. 187 | def decrypt_block(block) 188 | xl, xr = block.unpack('NN') 189 | xl, xr = decrypt_pair(xl, xr) 190 | decrypted = [xl, xr].pack('NN') 191 | return(decrypted) 192 | end 193 | 194 | # Block size. Currently this is fixed at 8. 195 | def block_size 196 | 8 197 | end 198 | 199 | # 200 | def encrypt_pair(xl, xr) 201 | 3.times { 202 | xr ^= f(xl+@key[0]) 203 | xl ^= f(xr+@key[1]) 204 | xr ^= f(xl+@key[2]) 205 | xl ^= f(xr+@key[3]) 206 | xr ^= f(xl+@key[4]) 207 | xl ^= f(xr+@key[5]) 208 | xr ^= f(xl+@key[6]) 209 | xl ^= f(xr+@key[7]) 210 | } 211 | xr ^= f(xl+@key[7]) 212 | xl ^= f(xr+@key[6]) 213 | xr ^= f(xl+@key[5]) 214 | xl ^= f(xr+@key[4]) 215 | xr ^= f(xl+@key[3]) 216 | xl ^= f(xr+@key[2]) 217 | xr ^= f(xl+@key[1]) 218 | xl ^= f(xr+@key[0]) 219 | return([xr, xl]) 220 | end 221 | 222 | # 223 | def decrypt_pair(xl, xr) 224 | xr ^= f(xl+@key[0]) 225 | xl ^= f(xr+@key[1]) 226 | xr ^= f(xl+@key[2]) 227 | xl ^= f(xr+@key[3]) 228 | xr ^= f(xl+@key[4]) 229 | xl ^= f(xr+@key[5]) 230 | xr ^= f(xl+@key[6]) 231 | xl ^= f(xr+@key[7]) 232 | 3.times { 233 | xr ^= f(xl+@key[7]) 234 | xl ^= f(xr+@key[6]) 235 | xr ^= f(xl+@key[5]) 236 | xl ^= f(xr+@key[4]) 237 | xr ^= f(xl+@key[3]) 238 | xl ^= f(xr+@key[2]) 239 | xr ^= f(xl+@key[1]) 240 | xl ^= f(xr+@key[0]) 241 | } 242 | return([xr, xl]) 243 | end 244 | 245 | # 246 | def f(longWord) 247 | longWord = longWord % ULONG 248 | a, b, c, d = [longWord].pack('L').unpack('CCCC') 249 | return(sTable[3][d] ^ sTable[2][c] ^ sTable[1][b] ^ sTable[0][a]) 250 | end 251 | 252 | # 253 | def generate_initialization_vector(words) 254 | srand(Time.now.to_i) 255 | vector = "" 256 | words.times { 257 | vector << [rand(ULONG)].pack('N') 258 | } 259 | return(vector) 260 | end 261 | 262 | # 263 | def carefully_open_file(filename, mode) 264 | begin 265 | aFile = File.new(filename, mode) 266 | rescue 267 | puts "Sorry. There was a problem opening the file <#{filename}>." 268 | aFile.close() unless aFile.nil? 269 | raise 270 | end 271 | return(aFile) 272 | end 273 | 274 | # Binary XOR of two strings. 275 | # 276 | # puts "\000\000\001\001" ^ "\000\001\000\001" 277 | # puts "\003\003\003" ^ "\000\001\002" 278 | # 279 | # _produces_ 280 | # 281 | # "\000\001\001\000" 282 | # "\003\002\001" 283 | # 284 | # NOTE: This used to be a String#^ extension in v1.0. So if 285 | # an uncaught bug should arise check this first. 286 | # 287 | def xor(str1, str2) 288 | a = str1.unpack('C'*(str1.length)) #.bytes.to_a 289 | b = str2.unpack('C'*(str2.length)) #.bytes.to_a 290 | if (b.length < a.length) 291 | (a.length - b.length).times { b << 0 } 292 | end 293 | xor = "" 294 | 0.upto(a.length - 1) do |pos| 295 | x = a[pos] ^ b[pos] 296 | xor << x.chr() 297 | end 298 | return(xor) 299 | end 300 | 301 | end 302 | 303 | # Copyright (c) 2007 Rubyworks. All rights reserved. 304 | --------------------------------------------------------------------------------