gfc64 0.0.2 → 0.0.3

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
  SHA256:
3
- metadata.gz: f93c96115de165e7cec9824e893e7254b6612c5d254c19d19c14899c7aa68ef1
4
- data.tar.gz: 00fc60e41ebe8a82bd7de95386aaa097df8a468ecb13e1ad98c7a4b5a311f59c
3
+ metadata.gz: 925a9e68e6edfd9f2d40a0e37f7712b56e113382a35f46ed6ff10319518e8bca
4
+ data.tar.gz: 821817a8b6df2d28e61783676242e7ece64a868b764ce7a10defad2ad58ec6b2
5
5
  SHA512:
6
- metadata.gz: 2b7b53943801d158fbc1e44c2a9bd6038aa4445047ebfc7de941f3dc583bb55120e9353dbea6d12de4253d1bc67f88c44e4a1c2326a549f4dd13a6a0842e2041
7
- data.tar.gz: 6674b80a4457530858aa15b57d89b421431e81313066356d95013292257b160936efde74b27349f410d5cc002dc64bf5dfe9fb00f08af830d72c5dfb2268a617
6
+ metadata.gz: a8f8f4055326bd37ae278fffbb3ae1f5ba04116dd949686df673fb03466c70da7eea23c31a9303a6b927da63e59d9b777c7fbfea4484cbc8eba03a0b3379d3b3
7
+ data.tar.gz: 0a9a328a725f9fcd43fdf479e04eaca93f102facf2276a600d206c1369acc107ce94631d342cc92ebfd2e3e34a65d7a48eb310e3e046e6b3e334ce28c4c65c3f
data/README.md CHANGED
@@ -1,20 +1,39 @@
1
1
  # GFC64
2
2
 
3
- Format-preserving Generalized Feistel Cipher for 64-bit integers. Encrypts 64-bit
4
- integers into... 64-bit integers!
3
+ Encrypt 64-bit integers into other 64-bit integers without collisions.
5
4
 
6
- Very useful for if you have sequential 64-bit integer database primary keys that
7
- you want to expose in an app, but you don't want to leak count information
8
- (e.g. `/customers/1`, `/customers/2`, ...), and you don't want to add another
9
- column to store something auxiliary like a UUID.
5
+ Useful for hiding database auto-incrementing primary keys without needing
6
+ to store additional data (like a UUID field).
10
7
 
11
- For example, with this gem, routes like
8
+ For example, say you have a web app where routes are stored like `/customers/:id`
9
+ so that you have exposed URL paths like this:
12
10
 
13
- `/customers/1` can become something like `/customers/4552956331295818987`, and
11
+ `/customers/1`
14
12
 
15
- `/customers/2` can become something like `/customers/3833777695217202560`
13
+ `/customers/2`
16
14
 
17
- ## Usage
15
+ With this gem, you can (at view-time) encrypt the above IDs into different IDs
16
+ so that you get these paths instead, without storing any additional data:
17
+
18
+ `/customers/4552956331295818987` (the backend decrypts this into `/customers/1`)
19
+
20
+ `/customers/3833777695217202560` (the backend decrypts this into `/customers/2`)
21
+
22
+ All while keeping your auto-incrementing, sequential IDs in your database and
23
+ getting all the benefits of a standard database index.
24
+
25
+ The encryption is achieved by implementing a format-preserving
26
+ [Generalized Feistel Cipher][paper].
27
+
28
+ ## Installation
29
+
30
+ Add to your `Gemfile`:
31
+
32
+ ```ruby
33
+ gem "gfc64"
34
+ ```
35
+
36
+ ## General Usage
18
37
 
19
38
  ```ruby
20
39
  key = SecureRandom.hex(32) # => "ffb5e3600fc27924f97dc055440403b10ce97160261f2a87eee576584cf942e5"
@@ -25,6 +44,48 @@ gfc.encrypt(2) # => 3833777695217202560
25
44
  gfc.decrypt(3833777695217202560) # => 2
26
45
  ```
27
46
 
47
+ ## Rails Usage
48
+
49
+ For Rails, there's an ActiveRecord mixin which adds `#gfc_id` and
50
+ `#to_param` methods and a `::find_gfc` class method. By setting `#to_param`,
51
+ resource path helpers like `customer_path(@customer)` automatically use the
52
+ GFC encrypted ID.
53
+
54
+ Example usage:
55
+
56
+ ```ruby
57
+ # app/models/customer.rb
58
+
59
+ class Customer < ApplicationRecord
60
+ include GFC64::ActiveRecord[GFC64.new(ENV['GFC_KEY'])]
61
+ # or the argument can be a proc/lambda if you need late binding:
62
+ # include GFC64::ActiveRecord[-> { GFC64.new(ENV['GFC_KEY']) }]
63
+ end
64
+ ```
65
+
66
+ For retrieval, use `::find_gfc`:
67
+
68
+ ```ruby
69
+ # app/controllers/customers_controller.rb
70
+
71
+ class CustomersController < ApplicationController
72
+ def show
73
+ @customer = Customer.find_gfc(params[:id])
74
+ end
75
+ end
76
+ ```
77
+
78
+ ## Potential drawbacks
79
+
80
+ Ruby's dynamic typing means we're just passing bare Integers around, so it's
81
+ possible to make a mistake where you write something like `Model.find(gfc_id)`
82
+ and return a completely unexpected record because you forgot to decrypt the ID.
83
+
84
+ With a type system it would be trivial to prevent these errors. However, the
85
+ space of 64-bit integers is very large, and encrypted IDs tend to occupy numbers
86
+ much higher than most web apps will ever reach, so more than likely this sort of
87
+ error would be discovered quickly as queries fail to find anything.
88
+
28
89
  ## Disclaimer
29
90
 
30
91
  This code has not been vetted by a security audit or a professional
@@ -0,0 +1,37 @@
1
+ class GFC64
2
+ module ActiveRecord
3
+ def self.[](gfc)
4
+ Module.new do
5
+ include ActiveRecord
6
+
7
+ define_singleton_method :included do |klass|
8
+ klass.extend(ClassMethods)
9
+ klass.send(:include, InstanceMethods)
10
+ klass.f_gfc = gfc
11
+ end
12
+ end
13
+ end
14
+
15
+ module ClassMethods
16
+ attr_accessor :f_gfc
17
+
18
+ def gfc
19
+ @gfc ||= f_gfc.respond_to?(:call) ? f_gfc.call : f_gfc
20
+ end
21
+
22
+ def find_gfc(gfc_id)
23
+ find(gfc.decrypt(gfc_id))
24
+ end
25
+ end
26
+
27
+ module InstanceMethods
28
+ def gfc_id
29
+ id && self.class.gfc.encrypt(id)
30
+ end
31
+
32
+ def to_param
33
+ gfc_id.to_s
34
+ end
35
+ end
36
+ end
37
+ end
data/lib/gfc64.rb CHANGED
@@ -4,7 +4,7 @@ require "openssl"
4
4
  require "securerandom"
5
5
 
6
6
  class GFC64
7
- VERSION = "0.0.2".freeze
7
+ VERSION = "0.0.3".freeze
8
8
 
9
9
  attr_reader :rounds, :key, :block_size
10
10
 
@@ -55,3 +55,5 @@ class GFC64
55
55
  OpenSSL::Digest::SHA256.digest(key + [round].pack('L'))[0...16] # Truncate to 128 bits for AES key
56
56
  end
57
57
  end
58
+
59
+ require "gfc64/active_record"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gfc64
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abe Voelker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-03 00:00:00.000000000 Z
11
+ date: 2023-11-04 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Hides sequential primary key counts without resorting to UUIDs or GUIDs.
14
14
  email: abe@abevoelker.com
@@ -18,6 +18,7 @@ extra_rdoc_files: []
18
18
  files:
19
19
  - README.md
20
20
  - lib/gfc64.rb
21
+ - lib/gfc64/active_record.rb
21
22
  homepage: https://github.com/abevoelker/gfc64
22
23
  licenses:
23
24
  - MIT
@@ -34,7 +35,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
34
35
  requirements:
35
36
  - - ">="
36
37
  - !ruby/object:Gem::Version
37
- version: 2.1.0
38
+ version: 2.4.0
38
39
  required_rubygems_version: !ruby/object:Gem::Requirement
39
40
  requirements:
40
41
  - - ">="