scl 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 043a75c0ec7aab24c5bde01c147e009b7e0bc58f
4
+ data.tar.gz: 3e1bf4954baccfab324591cddcbaa1fc60f14dab
5
+ SHA512:
6
+ metadata.gz: eb615f84d442a67a169c804f99a2a243553c99055879a52d7479e96742f43142e69da4971657f6ead3d19bea5584f3722553e7b64193f563507e6950fe19dd2a
7
+ data.tar.gz: c0f3e20309a25ff69d1e4ebb2dcfaf8e2275fee1ebd7fa48cbefeb6d379ad9a4fb1b72e0d3c2b64cceb593e26755e065be4c3bdb40095533ed71a7ab8e430c6b
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at wouter@youdo.co.nz. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in scl.gemspec
6
+ gemspec
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Scl (Simple Crypto Library)
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/scl`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'scl'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install scl
22
+
23
+ ## CLI
24
+
25
+ SCL Comes with a command line interface that allows you to perform basic encryption, decryption and key generation and key negotiation operations.
26
+
27
+ Example usage:
28
+
29
+ ```
30
+ RSA:
31
+ scl rsa generate # Generate an RSA key-pair > prints to stdout in base64
32
+ scl rsa generate --size=2048 --out=/tmp/keypair # Generate an RSA key-pair with size 2048 and
33
+ # output binary as binary encoded.
34
+ # Save to path /tmp/keypair
35
+
36
+ scl rsa verify --pub-key=/tmp/keypair/rsa.pub /path/to/file "signature" # Verify the signature of a file using a public key
37
+ scl rsa sign --priv-key=/tmp/keypair/rsa.priv /path/to/file # Generate a signature, outputs to stdout
38
+ scl rsa encrypt --key=/tmp/keypair/rsa.[priv|pub] /path/to/file # Encrypt a file, output to stdout
39
+ scl rsa decrypt --key=/tmp/keypair/rsa.[priv|pub] /path/to/file # Decrypt a file, output to stdout
40
+
41
+ encrypt and decrypt both accept optional --cipher-size/-cs arguments
42
+ All rsa actions accept --format/--input-format/--output-format -f/-if/-of arguments
43
+
44
+ DH:
45
+ scl dh ping # Start a diffie hellman key-generation
46
+ scl dh pong [der] [public-key] # Complete side-1 of a diffie hellman key-generation
47
+ scl dh done [der] [public-key] [priv-key] # Complete side-2 of a diffie hellman key-generation
48
+
49
+ AES:
50
+ scl aes encrypt # Encrypt from stdin
51
+ scl aes encrypt [file] # Encrypt from file
52
+ scl aes encrypt --key="abc" [file] # Enc
53
+ ```
54
+
55
+ ## Usage
56
+
57
+ TODO: Write usage instructions here
58
+
59
+ ## Development
60
+
61
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
62
+
63
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
64
+
65
+ ## Contributing
66
+
67
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/scl. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
68
+
69
+ ## Code of Conduct
70
+
71
+ Everyone interacting in the Scl project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/scl/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "scl"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ require 'pry-byebug'
11
+ Pry.start
12
+
13
+ # require "irb"
14
+ # IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/scl ADDED
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "scl"
5
+ require 'optparse'
6
+ require 'pry-byebug'
7
+
8
+ Options = Struct.new(
9
+ :input_format,
10
+ :output_format,
11
+ :key_format,
12
+ :module,
13
+ :action,
14
+ :verbose,
15
+ :key_path,
16
+ :key_size,
17
+ :private_key_file,
18
+ :public_key_file,
19
+ :output_file,
20
+ :min_shares,
21
+ :num_shares,
22
+ :block_size,
23
+ :block_cipher,
24
+ :digest,
25
+ :help,
26
+ :opts
27
+ )
28
+
29
+ args = Options.new()
30
+ opt_parser = OptionParser.new do |opts|
31
+ opts.banner = "Usage: scl [mode] [command] [options] "
32
+
33
+ opts.separator ""
34
+ opts.separator "Where mode is one of (aes, rsa, dh, sss, digest)"
35
+ opts.separator "try scl [mode] -h or scl [mode] [command] -h for more details"
36
+ opts.separator ""
37
+ opts.separator "Where options are:"
38
+
39
+ opts.on("-v", "--verbose", "Verbose output") do
40
+ args.verbose = true
41
+ end
42
+
43
+ opts.on(%i(words qrcode base64 binary hex stdout), "-f [FORMAT]", "--format [=FORMAT]", "Format to use for output, one of base64, qrcode, words, hex, stdout, none") do |f|
44
+ puts "Selected output format #{f}" if args.verbose
45
+ args.output_format = f
46
+ end
47
+
48
+ opts.on(%i(words qrcode base64 binary hex), "-i [INPUT_FORMAT]", "--input-format [=INPUT_FORMAT]", "Format to use for input, one of base64, qrcode, words, hex, none") do |f|
49
+ puts "Selected input format #{f}" if args.verbose
50
+ args.input_format = f
51
+ end
52
+
53
+ opts.on(%i(words qrcode base64 binary hex), "-b [KEY_FORMAT]", "--key-format [=KEY_FORMAT]", "Format to use for keys, one of base64, qrcode, words, hex, none") do |f|
54
+ puts "Selected key format #{f}" if args.verbose
55
+ args.key_format = f
56
+ end
57
+
58
+ opts.on("-k [KEY_PATH]", "--key-path [=KEY_PATH]", "The path of the key(s) to use (Looks for [key_path].pub and [key_path].priv)") do |p|
59
+ puts "Selected key path #{p}" if args.verbose
60
+ args.key_path = p
61
+ end
62
+
63
+ opts.on("-Z [PRIVATE_KEY]", "--priv-key [=PRIVATE_KEY]", "Private key file to use") do |p|
64
+ puts "Using private key file #{p}" if args.verbose
65
+ args.private_key_file = p
66
+ end
67
+
68
+ opts.on("-p [PUBLIC_KEY]", "--pub-key [=PUBLIC_KEY]", "Public key file to use") do |p|
69
+ puts "Using public key file #{p}" if args.verbose
70
+ args.public_key_file = p
71
+ end
72
+
73
+ opts.on("-o [OUTPUT_FILE]", "--out [=OUTPUT_FILE]", "File or file-prefix for where to save outputs") do |p|
74
+ puts "Using output file #{p}" if args.verbose
75
+ args.output_file = p
76
+ end
77
+
78
+ opts.on("-s [KEY_SIZE]", "--key-size [=KEY_SIZE]", Integer, "Size of the generated key") do |ks|
79
+ puts "Using key size #{ks}" if args.verbose
80
+ args.key_size = ks
81
+ end
82
+
83
+ opts.on("-m [MIN_SHARES]", "--min-shares [=MIN_SHARES]", Integer, "Size of the generated key") do |ms|
84
+ puts "Using min shares #{ms}" if args.verbose
85
+ args.min_shares = ms
86
+ end
87
+
88
+ opts.on("-n [NUM_SHARES]", "--num-shares [=NUM_SHARES]", Integer, "Size of the generated key") do |ns|
89
+ puts "Using num shares #{ns}" if args.verbose
90
+ args.num_shares = ns
91
+ end
92
+
93
+ opts.on("-S [BLOCK_SIZE]", "--block-size [=BLOCK_SIZE]", Integer, "Block size of cipher") do |bs|
94
+ puts "Using block size #{bs}" if args.verbose
95
+ args.block_size = bs
96
+ end
97
+
98
+ opts.on("-C [BLOCK_CIPHER]", "--block-size [=BLOCK_CIPHER]", String, "Block cipher") do |bc|
99
+ puts "Using block cipher #{bc}" if args.verbose
100
+ args.block_cipher = bc
101
+ end
102
+
103
+ opts.on('-d [DIGEST]', '--digest [=DIGEST]', String, 'Digest (e.g. sha256)') do |dg|
104
+ puts "Using digest #{dg}" if args.verbose
105
+ args.digest = dg
106
+ end
107
+
108
+ opts.on("-h", "--help", "Prints this help") do
109
+ args.help = true
110
+ end
111
+ args.opts = opts
112
+
113
+ end
114
+
115
+ opt_parser.parse!
116
+
117
+ unless ARGV.any?
118
+ puts args.opts
119
+ exit(0)
120
+ else
121
+ Scl::Control::Controller.new(args)
122
+ .module(ARGV.shift)
123
+ .action(ARGV.shift, ARGV)
124
+ end
data/lib/scl/aes.rb ADDED
@@ -0,0 +1,28 @@
1
+ module Scl
2
+ class AES
3
+ def initialize(block_size=256, block_cipher=:CBC)
4
+ @block_cipher = block_cipher || :CBC
5
+ @block_size = block_size || 256
6
+ end
7
+
8
+ def build_cypher
9
+ OpenSSL::Cipher::AES.new(@block_size, @block_cipher)
10
+ end
11
+
12
+ def encrypt(plaintext, key=nil, iv=nil)
13
+ block_cipher = build_cypher
14
+ block_cipher.encrypt
15
+ block_cipher.key = key ||= block_cipher.random_key
16
+ block_cipher.iv = iv ||= block_cipher.random_iv
17
+ [block_cipher.update(plaintext) + block_cipher.final, key, iv]
18
+ end
19
+
20
+ def decrypt(ciphertext, key, iv)
21
+ block_cipher = build_cypher
22
+ block_cipher.decrypt
23
+ block_cipher.key = key
24
+ block_cipher.iv = iv
25
+ block_cipher.update( ciphertext ) + block_cipher.final
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,51 @@
1
+ module Scl
2
+ module Control
3
+ class AES < ControllerModule
4
+
5
+ help <<-HELP,
6
+ encrypt. Encrypt a given file.
7
+ Can optionally be given an existing key, otherwise a unique one will be generated alongside
8
+ the cipher text.
9
+ e.g
10
+ scl aes encrypt somefile
11
+ scl aes encrypt somefile -k somekey
12
+ HELP
13
+ def encrypt(file)
14
+ input_key = args.key_path ?
15
+ read_file(args.key_path) :
16
+ nil
17
+ file_content = read_file(file)
18
+ ct, key, iv = aes.encrypt(file_content, input_key)
19
+ args.output_file ||= file
20
+ controller.output(
21
+ Output.new(iv << '::' << ct, ".enc"),
22
+ input_key ? nil : Output.new(key, '.key')
23
+ )
24
+ end
25
+
26
+
27
+ help <<-HELP,
28
+ decrypt. Decrypt a given file.
29
+ Must be given a key using -k/--key-path
30
+ e.g
31
+ scl aes decrypt somefile.enc -k somekey.key
32
+ scl aes decrypt somefile.enc -k somekey.key -o output.txt
33
+ HELP
34
+ def decrypt(file)
35
+ key = input_decoder.decode(read_file(args.key_path, "encryption key", "Use -k option"))
36
+ iv, cipher_text = input_decoder.decode(read_file(file, 'ciphertext')).split('::', 2)
37
+
38
+ plaintext = aes.decrypt(cipher_text, key, iv)
39
+ args.output_format = 'binary'
40
+ controller.output(
41
+ Output.new(plaintext, '')
42
+ )
43
+ end
44
+
45
+ private
46
+ def aes
47
+ Scl::AES.new(args.block_size, args.block_cipher)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,96 @@
1
+ module Scl
2
+ module Control
3
+ class Controller
4
+ attr_reader :args
5
+ def initialize(args)
6
+ @args = args
7
+ puts "Using output format #{output_encoder.name}" if verbose?
8
+ puts "Using input format #{input_decoder.name}" if verbose?
9
+ end
10
+
11
+ def output_encoder
12
+ coder_for(args.output_format)
13
+ end
14
+
15
+ def input_decoder
16
+ coder_for(args.input_format)
17
+ end
18
+
19
+ def key_coder
20
+ coder_for(args.key_format)
21
+ end
22
+
23
+ def output_file
24
+ "#{@args.output_file}".strip
25
+ end
26
+
27
+ def verbose?
28
+ @args.verbose
29
+ end
30
+
31
+ def module(module_name)
32
+ case module_name
33
+ when "aes" then Control::AES.new(self)
34
+ when "rsa" then Control::RSA.new(self)
35
+ when "dh" then Control::DH.new(self)
36
+ when "sss" then Control::SSS.new(self)
37
+ when "digest" then Control::Digest.new(self)
38
+ else
39
+ puts "No scl module found \"#{module_name}\""
40
+ puts args.opts
41
+ exit(1)
42
+ end
43
+ end
44
+
45
+ def coder_for(format)
46
+ case "#{format}".strip
47
+ when "base64" then Format::BASE64
48
+ when "qrcode" then Format::QRCODE
49
+ when "base64" then Format::BASE64
50
+ when "words" then Format::WORDS
51
+ when "hex" then Format::HEX
52
+ when "binary","text","none" then Format::BINARY
53
+ when "", "auto" then Format::AUTO
54
+ when "stdout" then Format::STDOUT
55
+ else
56
+ puts "Unexpected format \"#{format}\""
57
+ exit(1)
58
+ end
59
+ end
60
+
61
+ def output(*results)
62
+ case output_file
63
+ when '' then
64
+ puts "\n\n"
65
+ puts results.compact.map{|r| output_encoder.encode(r.content) }.join("\n\n")
66
+ else
67
+ results.compact.each do |result|
68
+ puts "Writing #{result.file(output_file)}" if verbose?
69
+ if args.output_format == 'stdout'
70
+ output_encoder.encode(result.content)
71
+ else
72
+ IO.write(
73
+ result.file(output_file),
74
+ output_encoder.encode(result.content)
75
+ ) if confirm_overwrite?(result.file(output_file))
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ def confirm_overwrite?(filename)
82
+ if File.exists?(filename)
83
+ puts "File #{filename} already exists. Confirm overwrite? [Yn]"
84
+ if gets.strip.downcase == 'y'
85
+ puts "Confirmed overwrite for #{filename}" if verbose?
86
+ return true
87
+ else
88
+ puts "Skipping save for #{filename}" if verbose?
89
+ return false
90
+ end
91
+ end
92
+ return true
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,102 @@
1
+ module Scl
2
+ module Control
3
+ class ControllerModule
4
+ attr_reader :controller
5
+ def initialize(controller)
6
+ @controller = controller
7
+ end
8
+
9
+ def args
10
+ @controller.args
11
+ end
12
+
13
+ def input_decoder
14
+ @controller.input_decoder
15
+ end
16
+
17
+ def output_encoder
18
+ @controller.output_encoder
19
+ end
20
+
21
+ def key_coder
22
+ @controller.key_coder
23
+ end
24
+
25
+ def help?
26
+ args.help
27
+ end
28
+
29
+ def self.help(message, method)
30
+ @@help ||= {}
31
+ @@help[self.name] ||= {}
32
+ @@help[self.name][method.to_s] = message
33
+ end
34
+
35
+ def self.print_help(args, method, own_methods=[])
36
+ module_name = self.name.split('::').last.downcase
37
+ puts "======="
38
+ if method && @@help[self.name] && @@help[self.name][method]
39
+ puts "Usage: scl #{module_name} #{method} (options)\n"
40
+ puts
41
+ puts @@help[self.name][method].split("\n").map{|line| line.gsub(/^\s{6}/,'')}.join("\n")
42
+ puts
43
+ else
44
+ puts "No help docs found for \"#{method}\"\n=======\n" if method
45
+ puts "Usage: scl #{module_name} [command] (options)"
46
+ puts
47
+ puts "Supported commands are [#{own_methods.join(' ')}]"
48
+ puts
49
+ puts "Try scl #{module_name} [command] -h for more info"
50
+ puts
51
+ puts args.opts.to_s[/Where options.*/m]
52
+ end
53
+ exit(0)
54
+ end
55
+
56
+ def action(action_name, args)
57
+ args = args.dup
58
+ ARGV.clear
59
+ if @controller.args.help || !action_name
60
+ self.class.print_help(@controller.args, action_name, self.public_methods.select{|m| self.method(m).owner == self.class })
61
+ exit(0)
62
+ end
63
+ if self.respond_to?(action_name)
64
+ begin
65
+ action = self.method(action_name)
66
+ required_args = action.arity >= 0 ? action.arity : -(action.arity + 1)
67
+ unless required_args <= args.length
68
+ raise ControlError.new("#{action_name} expected at least #{required_args} arguments\nE.g.\n#{action_name} #{action.parameters.map(&:last).map{|x| "[#{x}]"}[-required_args..-1].join(' ')} (options)")
69
+ end
70
+ self.send(action_name, *args)
71
+ rescue ArgumentError => e
72
+ puts e.message
73
+ puts "#{action_name} expects #{required_args} arguments by default\nE.g.\n#{action_name} #{action.parameters.map(&:last).map{|x| "[#{x}]"}[-required_args..-1].join(' ')}"
74
+ self.class.print_help(@controller.args, action_name)
75
+ puts e.backtrace if @controller.verbose?
76
+ rescue ControlError => e
77
+ puts e.message
78
+ puts e.cause
79
+ puts e.cause.backtrace if @controller.verbose?
80
+ self.class.print_help(@controller.args, action_name)
81
+ end
82
+ else
83
+ own_methods = self.public_methods.select{|m| self.method(m).owner == self.class }
84
+ puts "Command not supported: \"#{action_name}\""
85
+ puts "Supported commands are [#{own_methods.join(' ')}]"
86
+ exit(1)
87
+ end
88
+ end
89
+
90
+ private
91
+ def read_file(file, label='', help)
92
+ unless file
93
+ raise ControlError.new("Expected #{label} file not given\n#{help}")
94
+ end
95
+ unless File.exists?(file)
96
+ raise ControlError.new("Expected #{label} file #{file} doesnt exist\n#{help}")
97
+ end
98
+ IO.read(file)
99
+ end
100
+ end
101
+ end
102
+ end