urlcrypt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,53 @@
1
+ # URLcrypt
2
+
3
+ Ever wanted to securely transmit (not too long) pieces of arbitrary binary data
4
+ in a URL? *urlencrypt* makes it easy!
5
+
6
+ This gem is based on the base32 gem from Samuel Tesla.
7
+
8
+ URLcrypt uses a 256-bit AES symmetric encryption to securely encrypt data, and
9
+ and encodes and decodes Base 62 strings that can be used directly in URLs.
10
+
11
+ For example, this can be used to securely store user ids and the like when you
12
+ access a web application from a place that doesn't have other authentication
13
+ mechanisms, like when you load an image in an email.
14
+
15
+ URLcrypt uses a modified Base 32 algorithm that doesn't use padding characters,
16
+ and doesn't use vowels to avoid bad words in the generated string.
17
+
18
+ The main reason why Base 32 is useful is that Ruby's built-in Base 64 support
19
+ is, IMO, looking ugly in URLs and requires several characters that need to be
20
+ URL-escaped.
21
+
22
+ Unfortunately, some other gems out there that in theory could handle this
23
+ (like the radix gem) fail with strings that start with a "\0" byte.
24
+
25
+ *WORD OF WARNING* THERE IS NO GUARANTEE WHATSOEVER THAT THIS GEM IS ACTUALLY
26
+ SECURE AND WORKS. USE AT YOUR OWN RISK.
27
+
28
+ Note: this is version 0.0.1 which doesn't actually come with the encryption part
29
+ just yet. It will only work on Ruby 1.8.7 for now.
30
+
31
+ Patches are welcome, please include tests.
32
+
33
+ ## Installation
34
+
35
+ Add the `urlcrypt` gem to your Gemfile.
36
+
37
+ ## Simple Example
38
+
39
+ ```ruby
40
+ URLcrypt.encode('chunky bacon!') # => "mnAhk6tlp2qg2yldn8xcc"
41
+ URLcrypt.decode('mnAhk6tlp2qg2yldn8xcc') # => "chunky bacon!"
42
+ ```
43
+
44
+ ## Running the Test Suite
45
+
46
+ If you want to run the automated tests for URLcrypt, issue this command from the
47
+ distribution directory.
48
+
49
+ % rake test:all
50
+
51
+ ## References
52
+
53
+ * Base 32: RFC 3548: http://www.faqs.org/rfcs/rfc3548.html
@@ -0,0 +1,54 @@
1
+ # Copyright (c) 2013 Thomas Fuchs
2
+ # Copyright (c) 2007-2011 Samuel Tesla
3
+
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ require File.join(File.dirname(__FILE__), 'config', 'environment.rb')
23
+ require 'rake/clean'
24
+ require 'rake/testtask'
25
+ require 'rubygems'
26
+ require 'rubygems/package_task'
27
+
28
+ task :default => ['test:all']
29
+
30
+ gemspec = Gem::Specification.new do |s|
31
+ s.author = "Thomas Fuchs"
32
+ s.email = "thomas@slash7.com"
33
+ s.extra_rdoc_files = ["README.md"]
34
+ s.files = FileList["Rakefile", "{config,lib,test}/**/*"]
35
+ s.has_rdoc = true
36
+ s.name = 'urlcrypt'
37
+ s.require_paths << 'lib'
38
+ s.requirements << 'none'
39
+ s.summary = "Securely encode and decode short pieces of arbitrary binary data in URLs."
40
+ s.version = "0.0.1"
41
+ end
42
+
43
+ Gem::PackageTask.new(gemspec) do |pkg|
44
+ pkg.need_tar = true
45
+ end
46
+
47
+ namespace :test do
48
+ Rake::TestTask.new :all do |t|
49
+ t.libs << 'test'
50
+ t.pattern = 'test/**/*_test.rb'
51
+ t.verbose = true
52
+ end
53
+ Rake::Task['test:all'].comment = 'Run all of the tests'
54
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright (c) 2007-2011 Samuel Tesla
2
+
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ unless defined? BASE32_ROOT
22
+ root_path = File.join(File.dirname(__FILE__), '..')
23
+ BASE32_ROOT = File.expand_path(root_path)
24
+ end
25
+
26
+ $LOAD_PATH.unshift File.join(BASE32_ROOT, 'lib')
27
+ $LOAD_PATH.unshift File.join(BASE32_ROOT, 'ext')
@@ -0,0 +1,48 @@
1
+ module URLcrypt
2
+ # avoid vowels to not generate four-letter words, etc.
3
+ # this is important because those words can trigger spam
4
+ # filters when URLs are used in emails
5
+ TABLE = "1bcd2fgh3jklmn4pqrstAvwxyz567890".freeze
6
+
7
+ class Chunk
8
+ def initialize(bytes)
9
+ @bytes = bytes
10
+ end
11
+
12
+ def decode
13
+ bytes = @bytes.take_while {|c| c != 61} # strip padding
14
+ bytes = bytes.find_all{|b| !TABLE.index(b.chr).nil? } # remove invalid characters
15
+ n = (bytes.length * 5.0 / 8.0).floor
16
+ p = bytes.length < 8 ? 5 - (n * 8) % 5 : 0
17
+ c = bytes.inject(0) {|m,o| (m << 5) + TABLE.index(o.chr)} >> p
18
+ (0..n-1).to_a.reverse.collect {|i| ((c >> i * 8) & 0xff).chr}
19
+ end
20
+
21
+ def encode
22
+ n = (@bytes.length * 8.0 / 5.0).ceil
23
+ p = n < 8 ? 5 - (@bytes.length * 8) % 5 : 0
24
+ c = @bytes.inject(0) {|m,o| (m << 8) + o} << p
25
+ [(0..n-1).to_a.reverse.collect {|i| TABLE[(c >> i * 5) & 0x1f].chr},
26
+ ("=" * (8-n))] # TODO: remove '=' padding generation
27
+ end
28
+ end
29
+
30
+ def self.chunks(str, size)
31
+ result = []
32
+ bytes = str.bytes
33
+ while bytes.any? do
34
+ result << Chunk.new(bytes.take(size))
35
+ bytes = bytes.drop(size)
36
+ end
37
+ result
38
+ end
39
+
40
+ # strip '=' padding, because we don't need it
41
+ def self.encode(str)
42
+ chunks(str, 5).collect(&:encode).flatten.join.tr('=','')
43
+ end
44
+
45
+ def self.decode(str)
46
+ chunks(str, 8).collect(&:decode).flatten.join
47
+ end
48
+ end
@@ -0,0 +1,42 @@
1
+ require 'test/unit'
2
+ require 'URLcrypt'
3
+
4
+ class TestURLcrypt < Test::Unit::TestCase
5
+ def assert_decoding(encoded, plain)
6
+ decoded = URLcrypt.decode(encoded)
7
+ assert_equal(plain, decoded)
8
+ end
9
+
10
+ def assert_encoding(encoded, plain)
11
+ actual = URLcrypt.encode(plain)
12
+ assert_equal(encoded, actual)
13
+ end
14
+
15
+ def assert_encode_and_decode(encoded, plain)
16
+ assert_encoding(encoded, plain)
17
+ assert_decoding(encoded, plain)
18
+ end
19
+
20
+ def test_empty_string
21
+ assert_encode_and_decode('', '')
22
+ end
23
+
24
+ def test_encode
25
+ assert_encode_and_decode(
26
+ '111gc86f4nxw5zj1b3qmhpb14n5h25l4m7111',
27
+ "\0\0awesome \n ü string\0\0")
28
+ end
29
+
30
+ def test_invalid_encoding
31
+ assert_decoding('ZZZZZ', '')
32
+ end
33
+
34
+ def test_arbitrary_byte_strings
35
+ 0.step(1500,17) do |n|
36
+ original = (0..n).map{rand(256).chr}.join
37
+ encoded = URLcrypt::encode(original)
38
+ assert_decoding(encoded, original)
39
+ end
40
+ end
41
+
42
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: urlcrypt
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Thomas Fuchs
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-03-18 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description:
22
+ email: thomas@slash7.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.md
29
+ files:
30
+ - Rakefile
31
+ - config/environment.rb
32
+ - lib/URLcrypt.rb
33
+ - test/URLcrypt_test.rb
34
+ - README.md
35
+ homepage:
36
+ licenses: []
37
+
38
+ post_install_message:
39
+ rdoc_options: []
40
+
41
+ require_paths:
42
+ - lib
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ hash: 3
50
+ segments:
51
+ - 0
52
+ version: "0"
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ requirements:
63
+ - none
64
+ rubyforge_project:
65
+ rubygems_version: 1.8.24
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: Securely encode and decode short pieces of arbitrary binary data in URLs.
69
+ test_files: []
70
+