crypto-toolbox 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
-