crypto-toolbox 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6ebbbf499bc1a6995528e78213c05e6759fe5fc0
4
- data.tar.gz: 7d82492fd355fbcd89fe9d36c484c27ffce078e1
3
+ metadata.gz: e324bdda406627ce87188d30930b2345145c88ff
4
+ data.tar.gz: d263f209f0a9df40397b465de3bd7bd039e8288d
5
5
  SHA512:
6
- metadata.gz: b9565ca59c2857a1ee12d771f1e7003a1b0654707b6dd8c7586083dee52e8e740d450bfb55a496c4ff62166642e5e32d1d390adb4d1f975a25f47df7701452d0
7
- data.tar.gz: 9aecc7a4482ccf68f9ffa630998260eab13990bd9e4ac3bce6302f01e7aec1a04895939a60a77b84aa8dda62e410fbc170bf2dfe5412b3c508c966b5a2ecbcbd
6
+ metadata.gz: 4a788c9078e6580af052307b8781def44af3d6154c3dc325f30ebb9b769af18a8925f20d26bdd1ad8c93a9e3a66cc3874f21b33587a3940974cd1a38b46fade0
7
+ data.tar.gz: 1ef771f00df72e37dd20a834ddca7ada6a7f11a4fac03f701cbdf46d421f606d6a4ad00c17ca059dc3d2fe9f9cad619ca5f745108bcfc42b53f61e59721913bf
@@ -0,0 +1,133 @@
1
+
2
+ #require 'shellwords'
3
+ require 'ffi/hunspell'
4
+
5
+ =begin
6
+ # References:
7
+ #
8
+ # http://www.ulduzsoft.com/2015/03/breaking-the-vigenere-cipher/
9
+ # https://github.com/trekawek/vigenere/blob/master/vig.rb
10
+ #
11
+ =end
12
+ module Analyzers
13
+ class VigenereXor
14
+ def jot(message, debug: false)
15
+ if ENV["SEMI_AUTO_ANALYSIS"]
16
+ if debug == false || ENV["DEBUG_ANALYSIS"]
17
+ puts message
18
+ end
19
+ end
20
+ end
21
+ def print_delimiter_line
22
+ puts "====================================================================="
23
+ end
24
+
25
+ def find_pattern(buf)
26
+ bitstring = buf.bits.map{|b| b[0]}.join("")
27
+ 1.upto([buf.bytes.length,62].min).map do |ksize|
28
+ parts = bitstring.scan(/.{#{ksize}}/)
29
+ if parts.uniq.length == 1
30
+ parts.first
31
+ else
32
+ nil
33
+ end
34
+ end.compact.first
35
+ end
36
+
37
+ def analyze(input)
38
+ require "crypto-toolbox"
39
+ require "byebug"
40
+
41
+ buf = CryptBuffer.new(input)
42
+ result = find_pattern(buf)
43
+
44
+ if result.nil?
45
+ $stderr.puts "failed to find keylength by ASCII-8-Bit anlysis"
46
+ exit(1)
47
+ end
48
+
49
+ keylen = result.length
50
+ jot "Found recurring key pattern: #{result}"
51
+ jot "Detected key length: #{keylen}"
52
+
53
+ candidate_map ={}
54
+ (0..(keylen-1)).each do |key_byte|
55
+
56
+ nth_stream = (key_byte).step(buf.bytes.length() -1, keylen).map{|i| buf.bytes[i]}
57
+ smart_buf = CryptBuffer.new(nth_stream)
58
+
59
+ candidate_map[key_byte]=[]
60
+ 1.upto(255).each do |possible_key_value|
61
+ if smart_buf.xor_all_with(possible_key_value).bytes.all?{|e| e > 31 && e < 123 && e != 60 && e !=64}
62
+ jot("YES: " + smart_buf.xor_all_with(possible_key_value).to_s,debug: true)
63
+ candidate_map[key_byte] << possible_key_value
64
+ else
65
+ # the current byte does not create a plain ascii result ( thus skip it )
66
+ #jot "NO: " + smart_buf.xor_all_with(possible_key_value).to_s
67
+ end
68
+ end
69
+ end
70
+
71
+ head,*tail = candidate_map.map{|k,v|v}
72
+
73
+ jot "Amount of candidate keys: #{candidate_map.map{|k,v| v.length}.reduce(&:*)}. Starting Permutation (RAM intensive)"
74
+
75
+ combinations = head.product(*tail)
76
+ # make sure all permutations are still according to the bytes per position map
77
+ #x = combinations.select do |arr|
78
+ # #binding.pry
79
+ # arr.map.with_index{|e,i| candidate_map[i].include?(e) }.all?{|e| e ==true}
80
+ #end
81
+ if ENV["SEMI_AUTO_ANALYSIS"] && ENV["DEBUG_ANALYSIS"]
82
+ print_candidate_encryptions(candidate_map,keylen,buf)
83
+ end
84
+
85
+ result = KeySearch::Filter::AsciiPlain.new(combinations,buf).filter
86
+ unless result.empty?
87
+ jot "[Success] Found valid result(s)"
88
+ result.each do |r|
89
+ print_delimiter_line
90
+ jot r.xor(buf).str
91
+ print_delimiter_line
92
+ end
93
+ end
94
+
95
+
96
+ end
97
+
98
+ def print_candidate_encryptions(candidate_map,keylen,buf)
99
+ # printout for debugging. (Manual analysis of the characters)
100
+ print "======= Decryption result of first #{keylen} bytes with all candidate keys =======\n"
101
+ (0..keylen-1).each do|i|
102
+ candidate_map[i].each do |byte|
103
+ print CryptBuffer.new(buf.bytes[i,keylen]).xor(byte).to_s + " "
104
+ end
105
+ print "\n"
106
+ end
107
+ print_delimiter_line
108
+ end
109
+
110
+ end
111
+ end
112
+
113
+ =begin
114
+ NOTE: we may at digram and trigram support?
115
+ #trigram="the "
116
+ #x = CryptBuffer.new(trigram)
117
+ =end
118
+
119
+ if $0 == __FILE__
120
+
121
+ input = ARGV[0] || "0xF96DE8C227A259C87EE1DA2AED57C93FE5DA36ED4EC87EF2C63AAE5B9A7EFFD673BE4ACF7BE8923CAB1ECE7AF2DA3DA44FCF7AE29235A24C963FF0DF3CA3599A70E5DA36BF1ECE77F8DC34BE129A6CF4D126BF5B9A7CFEDF3EB850D37CF0C63AA2509A76FF9227A55B9A6FE3D720A850D97AB1DD35ED5FCE6BF0D138A84CC931B1F121B44ECE70F6C032BD56C33FF9D320ED5CDF7AFF9226BE5BDE3FF7DD21ED56CF71F5C036A94D963FF8D473A351CE3FE5DA3CB84DDB71F5C17FED51DC3FE8D732BF4D963FF3C727ED4AC87EF5DB27A451D47EFD9230BF47CA6BFEC12ABE4ADF72E29224A84CDF3FF5D720A459D47AF59232A35A9A7AE7D33FB85FCE7AF5923AA31EDB3FF7D33ABF52C33FF0D673A551D93FFCD33DA35BC831B1F43CBF1EDF67F0DF23A15B963FE5DA36ED68D378F4DC36BF5B9A7AFFD121B44ECE76FEDC73BE5DD27AFCD773BA5FC93FE5DA3CB859D26BB1C63CED5CDF3FE2D730B84CDF3FF7DD21ED5ADF7CF0D636BE1EDB79E5D721ED57CE3FE6D320ED57D469F4DC27A85A963FF3C727ED49DF3FFFDD24ED55D470E69E73AC50DE3FE5DA3ABE1EDF67F4C030A44DDF3FF5D73EA250C96BE3D327A84D963FE5DA32B91ED36BB1D132A31ED87AB1D021A255DF71B1C436BF479A7AF0C13AA14794"
122
+ analyzer = Analyzers::VigenereXor.new.analyze(input)
123
+ end
124
+
125
+
126
+
127
+
128
+
129
+
130
+
131
+
132
+
133
+
@@ -10,7 +10,20 @@ module Ciphers
10
10
  def self.decipher(msg,shift)
11
11
  ::Ciphers::Caesar.new.decipher(msg,shift)
12
12
  end
13
+ =begin
14
+ Within encipher and decipher we use a regexp comparision.
15
+ Array lookups are must slower and byte comparision is a little faster,
16
+ but much more complicated
13
17
 
18
+
19
+ Alphabet letter lookup algorithm comparision:
20
+
21
+ Comparison: (see benchmarks/string_comparision.rb)
22
+ string.bytes.first == A : 3289762.7 i/s
23
+ string =~ [A-Za-Z] : 2010285.8 i/s - 1.64x slower
24
+ Letter Array include?(A): 76997.0 i/s - 42.73x slower
25
+
26
+ =end
14
27
  def encipher(message,shift)
15
28
  assert_valid_shift!(shift)
16
29
  real_shift = convert_shift(shift)
@@ -1,5 +1,7 @@
1
1
  require 'crypto-toolbox/crypt_buffer.rb'
2
2
  require 'crypto-toolbox/key_filter.rb'
3
3
  require 'crypto-toolbox/spell_checker.rb'
4
+
5
+ require 'crypto-toolbox/analyzers/vigenere_xor.rb'
4
6
  require 'crypto-toolbox/ciphers/caesar.rb'
5
7
  require 'crypto-toolbox/ciphers/rot13.rb'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crypto-toolbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dennis Sivia
@@ -46,7 +46,7 @@ extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
48
  - lib/crypto-toolbox.rb
49
- - lib/crypto-toolbox/break_vigenere.rb
49
+ - lib/crypto-toolbox/analyzers/vigenere_xor.rb
50
50
  - lib/crypto-toolbox/ciphers/caesar.rb
51
51
  - lib/crypto-toolbox/ciphers/rot13.rb
52
52
  - lib/crypto-toolbox/crypt_buffer.rb
@@ -1,97 +0,0 @@
1
- # coding: utf-8
2
- require_relative './crypt_buffer.rb'
3
- require_relative './key_filter.rb'
4
- require 'shellwords'
5
- require 'ffi/hunspell'
6
-
7
- ##
8
- # http://www.ulduzsoft.com/2015/03/breaking-the-vigenere-cipher/
9
- # https://github.com/trekawek/vigenere/blob/master/vig.rb
10
-
11
- def find_pattern(buf)
12
- bitstring = buf.bits.map{|b| b[0]}.join("")
13
- 1.upto([buf.bytes.length,62].min).map do |ksize|
14
- parts = bitstring.scan(/.{#{ksize}}/)
15
- if parts.uniq.length == 1
16
- parts.first
17
- else
18
- nil
19
- end
20
- end.compact.first
21
- end
22
-
23
- input = ARGV[0] || "F96DE8C227A259C87EE1DA2AED57C93FE5DA36ED4EC87EF2C63AAE5B9A7EFFD673BE4ACF7BE8923CAB1ECE7AF2DA3DA44FCF7AE29235A24C963FF0DF3CA3599A70E5DA36BF1ECE77F8DC34BE129A6CF4D126BF5B9A7CFEDF3EB850D37CF0C63AA2509A76FF9227A55B9A6FE3D720A850D97AB1DD35ED5FCE6BF0D138A84CC931B1F121B44ECE70F6C032BD56C33FF9D320ED5CDF7AFF9226BE5BDE3FF7DD21ED56CF71F5C036A94D963FF8D473A351CE3FE5DA3CB84DDB71F5C17FED51DC3FE8D732BF4D963FF3C727ED4AC87EF5DB27A451D47EFD9230BF47CA6BFEC12ABE4ADF72E29224A84CDF3FF5D720A459D47AF59232A35A9A7AE7D33FB85FCE7AF5923AA31EDB3FF7D33ABF52C33FF0D673A551D93FFCD33DA35BC831B1F43CBF1EDF67F0DF23A15B963FE5DA36ED68D378F4DC36BF5B9A7AFFD121B44ECE76FEDC73BE5DD27AFCD773BA5FC93FE5DA3CB859D26BB1C63CED5CDF3FE2D730B84CDF3FF7DD21ED5ADF7CF0D636BE1EDB79E5D721ED57CE3FE6D320ED57D469F4DC27A85A963FF3C727ED49DF3FFFDD24ED55D470E69E73AC50DE3FE5DA3ABE1EDF67F4C030A44DDF3FF5D73EA250C96BE3D327A84D963FE5DA32B91ED36BB1D132A31ED87AB1D021A255DF71B1C436BF479A7AF0C13AA14794"
24
-
25
- buf = CryptBuffer.new(input)
26
- result = find_pattern(buf)
27
-
28
- if result.nil?
29
- $stderr.puts "failed to find keylength by ASCII-8-Bit anlysis"
30
- exit(1)
31
- end
32
-
33
- keylen = result.length
34
- puts "Found recurring key pattern: #{result}"
35
- puts "Detected key length: #{keylen}"
36
-
37
- candidate_map ={}
38
- (0..(keylen-1)).each do |key_byte|
39
-
40
- nth_stream = (key_byte).step(buf.bytes.length() -1, keylen).map{|i| buf.bytes[i]}
41
- smart_buf = CryptBuffer.new(nth_stream)
42
-
43
- candidate_map[key_byte]=[]
44
- 1.upto(255).each do |possible_key_value|
45
- if smart_buf.xor_all_with(possible_key_value).bytes.all?{|e| e > 31 && e < 123 && e != 60 && e !=64}
46
- #puts "YES: " + smart_buf.xor_all_with(possible_key_value).to_s
47
- candidate_map[key_byte] << possible_key_value
48
- else
49
- #puts "NO: " + smart_buf.xor_all_with(possible_key_value).to_s
50
- end
51
- end
52
- end
53
-
54
-
55
-
56
- head,*tail = candidate_map.map{|k,v|v}
57
-
58
- puts "Amount of candidate keys: #{candidate_map.map{|k,v| v.length}.reduce(&:*)}. Starting Permutation (RAM intensive)"
59
-
60
- combinations = head.product(*tail)
61
- # make sure all permutations are still according to the bytes per position map
62
- #x = combinations.select do |arr|
63
- # #binding.pry
64
- # arr.map.with_index{|e,i| candidate_map[i].include?(e) }.all?{|e| e ==true}
65
- #end
66
-
67
- # printout for debugging. (Manual analysis of the characters)
68
- puts "======= Candidate decryption result of first #{keylen} bytes ======="
69
- (0..keylen-1).each do|i|
70
- candidate_map[i].each do |byte|
71
- print CryptBuffer.new(buf.bytes[i,keylen]).xor(byte).to_s + " "
72
- end
73
- print "\n"
74
- end
75
- puts "====================================================================="
76
-
77
-
78
- result = KeySearch::Filter::AsciiPlain.new(combinations,buf).filter
79
- unless result.empty?
80
- puts "[Success] Found valid result(s)"
81
- result.each do |r|
82
- puts r.xor(buf).str
83
- end
84
- end
85
-
86
- =begin
87
- NOTE: we may at digram and trigram support?
88
- #trigram="the "
89
- #x = CryptBuffer.new(trigram)
90
- =end
91
-
92
-
93
-
94
-
95
-
96
-
97
-