obfuscurity 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in obfuscurity.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Graham Ashton
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,116 @@
1
+ # Obfuscurity
2
+
3
+ Have you ever needed to generate a unique number for a piece of data (a
4
+ little like a primary key) that's exposed to your customers? You might
5
+ use your database's primary key, but you don't want to expose an
6
+ internal counter that could give away sensitive information.
7
+
8
+ An **order number in a billing system** is a good example; until you've
9
+ processed thousands of orders you won't want people to know just how
10
+ young your business it (in some cases, it doesn't instil confidence).
11
+
12
+ Or perhaps you don't want your competitors to be able to work out **how
13
+ many people have signed up for your web app**, but want to include a
14
+ customer number in the URL? If you were to use an incrementing field
15
+ from your database, that information becomes painfully apparent.
16
+
17
+ The obvious solution (generating a random number and checking to see
18
+ whether it's already in use) feels like a hack, and performance starts
19
+ to suffer (because you find yourself generating numbers that have
20
+ already been used) quicker than you might expect.
21
+
22
+ Luckily, there's an easy solution, as outlined in [this comment][comment]
23
+ on StackOverflow. Just in case you don't have access to StackOverflow
24
+ right now, this is what it says:
25
+
26
+ > Pick a 8 or 9 digit number at random, say 839712541. Then, take your
27
+ > order number's binary representation (for this example, I'm not using
28
+ > 2's complement), pad it out to the same number of bits (30), reverse it,
29
+ > and xor the flipped order number and the magic number.
30
+
31
+ [comment]: http://stackoverflow.com/a/612085/158841
32
+
33
+ (Don't worry if you didn't follow that)
34
+
35
+ It's rather ingenius, and allows you to take a random seed (e.g.
36
+ 839712541) and a incrementing series of numbers, and convert them into a
37
+ seemingly random series. You can then convert them back again simply by
38
+ reversing the approach.
39
+
40
+ Of course, this **isn't** a secure approach. Anybody with a computer and
41
+ plenty of time would be able to work out the pattern.
42
+
43
+ If you've got some numbers that you seriously need to protect, use
44
+ cryptography. Obscurity provides [no security at all][wikipedia].
45
+
46
+ [wikipedia]: http://en.wikipedia.org/wiki/Security_through_obscurity
47
+
48
+ ## Installation
49
+
50
+ Add this line to your application's Gemfile:
51
+
52
+ gem 'obfuscurity'
53
+
54
+ And then execute:
55
+
56
+ $ bundle
57
+
58
+ Or install it yourself as:
59
+
60
+ $ gem install obfuscurity
61
+
62
+ ## Usage
63
+
64
+ To obfuscate the number you want to hide, make yourself a `Baffler`:
65
+
66
+ baffler = Obfuscurity::Baffler.new
67
+ baffler.obfuscate(1) # -> 302841629
68
+ baffler.obfuscate(2) # -> 571277085
69
+
70
+ If you later want to convert back to your primary key, use the clarify
71
+ method:
72
+
73
+ baffler.clarify(302841629) # -> 1
74
+ baffler.clarify(571277085) # -> 2
75
+
76
+ The `Baffler` object just happens to convert `1` to `302841629` because
77
+ of the seed that it's using (see the [StackOverflow comment][comment]
78
+ for details).
79
+
80
+ ### Configuring behaviour
81
+
82
+ If you'd like to use a different sequence specify a different seed when
83
+ you create the `Baffler` instance:
84
+
85
+ baffler = Obfuscurity::Baffler.new(seed: 61493749)
86
+
87
+ You'll no doubt have noticed that the numbers produced by default are
88
+ rather large. The algorithm uses a fixed number of bits (30 by default),
89
+ so any number as large as `2 ** 30` could be returned by the `obfuscate`
90
+ method.
91
+
92
+ If you know you won't need anything like that many unique numbers you
93
+ can reduce the number of bits:
94
+
95
+ baffler = Obfuscurity::Baffler.new(max_bits: 16)
96
+ baffler.obfuscate(42) # -> 21505
97
+
98
+ Just be aware that the maximum number of unique numbers that you can
99
+ cope with is `2 ** max_bits`, or in the case of 16 bits, just 32768
100
+ (which isn't a lot).
101
+
102
+ If you attempt to obfuscate a number that's too big to fit in the number
103
+ space available (i.e. you exceed the value set for `max_bits`) a
104
+ `Obfuscurity::Error` exception will be raised.
105
+
106
+ ## Contributing
107
+
108
+ 1. Fork it
109
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
110
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
111
+ 4. Push to the branch (`git push origin my-new-feature`)
112
+ 5. Create new Pull Request
113
+
114
+ ## Credits
115
+
116
+ Thanks to @benlovell for suggesting the name.
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,43 @@
1
+ require 'obfuscurity/version'
2
+
3
+ module Obfuscurity
4
+ class Error < RuntimeError; end
5
+
6
+ class Baffler
7
+ def initialize(params = {})
8
+ @seed = params.fetch(:seed, 839712541)
9
+ @max_bits = params.fetch(:max_bits, 30)
10
+ check_size_of_number_space(@seed)
11
+ end
12
+
13
+ def obfuscate(number)
14
+ check_size_of_number_space(number)
15
+ seed_bits = number_to_bits(@seed)
16
+ xor_bits = (0 ... seed_bits.size).map { |i| number[i] ^ seed_bits[i] }
17
+ bits_to_number(xor_bits)
18
+ end
19
+
20
+ def clarify(number)
21
+ bits = number_to_bits(number ^ @seed)
22
+ bits_to_number(bits.reverse)
23
+ end
24
+
25
+ private
26
+ def number_to_bits(number)
27
+ [].tap do |bits|
28
+ (@max_bits - 1).downto(0) { |i| bits << number[i] }
29
+ end
30
+ end
31
+
32
+ def bits_to_number(bits)
33
+ bits.inject(0) { |result, bit| (result << 1) | bit }
34
+ end
35
+
36
+ def check_size_of_number_space(number)
37
+ root = number ** (1.0 / @max_bits)
38
+ if root > 2
39
+ raise Error.new("#{number} requires more than #{@max_bits} bits")
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,3 @@
1
+ module Obfuscurity
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'obfuscurity/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "obfuscurity"
8
+ gem.version = Obfuscurity::VERSION
9
+ gem.authors = ["Graham Ashton"]
10
+ gem.email = ["graham@effectif.com"]
11
+ gem.description = <<-EOF
12
+ Sometimes exposing your app's internal counters (e.g. your database's
13
+ auto-incrementing primary keys) to the world is a bad idea. Maybe your
14
+ competitors will be able to work out how many orders you're making per
15
+ week, or your customers will be able to infer how many other customers
16
+ you've got. This gem will allow you to obscure those numbers so you can
17
+ use them in your URLs, your user interface, or as seemingly random order
18
+ numbers.
19
+ EOF
20
+ gem.summary = %q{Obfuscate your database ids, converting them to (seemingly) random numbers}
21
+ gem.homepage = "https://github.com/gma/obfuscurity"
22
+
23
+ gem.files = `git ls-files`.split($/)
24
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
25
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
26
+ gem.require_paths = ["lib"]
27
+
28
+ gem.add_development_dependency('nutrasuite')
29
+ gem.add_development_dependency('rake')
30
+ end
@@ -0,0 +1,52 @@
1
+ require 'test/unit'
2
+ require 'nutrasuite'
3
+
4
+ require_relative '../lib/obfuscurity'
5
+
6
+ class BafflerTest < MiniTest::Unit::TestCase
7
+ a 'Baffler' do
8
+ it 'should generate unique (repeatable) number from integer' do
9
+ # Wondering why the results are 302841629 and 571277085? See this
10
+ # thread on Stack Overflow:
11
+ #
12
+ # http://stackoverflow.com/questions/1179439/best-way-to-generate-order-numbers-for-an-online-store
13
+
14
+ 2.times do
15
+ assert_equal 302841629, Obfuscurity::Baffler.new.obfuscate(1)
16
+ end
17
+ assert_equal 571277085, Obfuscurity::Baffler.new.obfuscate(2)
18
+ end
19
+
20
+ it 'should convert an obfuscated number back into the original integer' do
21
+ baffler = Obfuscurity::Baffler.new
22
+
23
+ assert_equal 1, baffler.clarify(302841629)
24
+ assert_equal 2, baffler.clarify(571277085)
25
+
26
+ 10.times do |i|
27
+ n = baffler.obfuscate(i)
28
+ assert_equal i, baffler.clarify(n)
29
+ end
30
+ end
31
+
32
+ it 'allow you to control the size of the number space' do
33
+ baffler = Obfuscurity::Baffler.new(max_bits: 16, seed: 1)
34
+ assert_equal 21505, baffler.obfuscate(42)
35
+ end
36
+
37
+ it "should ensure that seed doesn't exceed available bits" do
38
+ max_bits = 30
39
+ too_big = (2 ** max_bits) + 1
40
+ assert_raises(Obfuscurity::Error) do
41
+ Obfuscurity::Baffler.new(max_bits: max_bits, seed: too_big)
42
+ end
43
+ end
44
+
45
+ it "should ensure that obscured numbers don't exceed available bits" do
46
+ baffler = Obfuscurity::Baffler.new
47
+ assert_raises(Obfuscurity::Error) do
48
+ baffler.obfuscate((2 ** 30) + 1)
49
+ end
50
+ end
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: obfuscurity
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Graham Ashton
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nutrasuite
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: ! 'Sometimes exposing your app''s internal counters (e.g. your database''s
47
+
48
+ auto-incrementing primary keys) to the world is a bad idea. Maybe your
49
+
50
+ competitors will be able to work out how many orders you''re making per
51
+
52
+ week, or your customers will be able to infer how many other customers
53
+
54
+ you''ve got. This gem will allow you to obscure those numbers so you can
55
+
56
+ use them in your URLs, your user interface, or as seemingly random order
57
+
58
+ numbers.
59
+
60
+ '
61
+ email:
62
+ - graham@effectif.com
63
+ executables: []
64
+ extensions: []
65
+ extra_rdoc_files: []
66
+ files:
67
+ - .gitignore
68
+ - Gemfile
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - lib/obfuscurity.rb
73
+ - lib/obfuscurity/version.rb
74
+ - obfuscurity.gemspec
75
+ - test/obfuscator_test.rb
76
+ homepage: https://github.com/gma/obfuscurity
77
+ licenses: []
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ segments:
89
+ - 0
90
+ hash: 2796161447218621274
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ segments:
98
+ - 0
99
+ hash: 2796161447218621274
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 1.8.23
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Obfuscate your database ids, converting them to (seemingly) random numbers
106
+ test_files:
107
+ - test/obfuscator_test.rb