Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 2 additions & 16 deletions app/services/encryption/encryptors/attribute_encryptor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,23 @@ def initialize
end

def encrypt(plaintext)
unless Figaro.env.attribute_encryption_without_kms == 'true'
return deprecated_encryptor.encrypt(plaintext)
end

aes_encrypted_ciphertext = aes_cipher.encrypt(plaintext, current_key)
encode(aes_encrypted_ciphertext)
end

def decrypt(ciphertext)
return deprecated_encryptor.decrypt(ciphertext) if legacy?(ciphertext)
raise EncryptionError, 'ciphertext invalid' unless valid_base64_encoding?(ciphertext)
decoded_ciphertext = decode(ciphertext)
try_decrypt(decoded_ciphertext)
end

def stale?
deprecated_encryptor&.stale? || stale
@stale
end

private

attr_reader :aes_cipher
attr_accessor :stale

def try_decrypt(decoded_ciphertext)
all_keys.each do |key|
Expand All @@ -42,16 +36,12 @@ def try_decrypt(decoded_ciphertext)
end

def try_decrypt_with_key(decoded_ciphertext, key)
self.stale = key != current_key
@stale = key != current_key
aes_cipher.decrypt(decoded_ciphertext, key)
rescue EncryptionError
nil
end

def legacy?(ciphertext)
Encryption::KmsClient.looks_like_kms?(ciphertext) || ciphertext.index('.')
end

def current_key
Figaro.env.attribute_encryption_key
end
Expand All @@ -63,10 +53,6 @@ def all_keys
def old_keys
JSON.parse(Figaro.env.attribute_encryption_key_queue)
end

def deprecated_encryptor
@_deprecated_encryptor ||= DeprecatedAttributeEncryptor.new
end
end
end
end

This file was deleted.

28 changes: 0 additions & 28 deletions app/services/encryption/encryptors/deprecated_session_encryptor.rb

This file was deleted.

10 changes: 0 additions & 10 deletions app/services/encryption/encryptors/session_encryptor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,19 @@ def encrypt(plaintext)
end

def decrypt(ciphertext)
return deprecated_encryptor.decrypt(ciphertext) if legacy?(ciphertext)

aes_ciphertext = KmsClient.new.decrypt(decode(ciphertext))
aes_encryptor.decrypt(aes_ciphertext, aes_encryption_key)
end

private

def legacy?(ciphertext)
ciphertext.index('.')
end

def aes_encryptor
AesEncryptor.new
end

def aes_encryption_key
Figaro.env.session_encryption_key[0...32]
end

def deprecated_encryptor
DeprecatedSessionEncryptor.new
end
end
end
end
3 changes: 0 additions & 3 deletions config/application.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ development:
attribute_cost: '4000$8$4$' # SCrypt::Engine.calibrate(max_time: 0.5)
attribute_encryption_key: '2086dfbd15f5b0c584f3664422a1d3409a0d2aa6084f65b6ba57d64d4257431c124158670c7655e45cabe64194f7f7b6c7970153c285bdb8287ec0c4f7553e25'
attribute_encryption_key_queue: '[{ "key": "11111111111111111111111111111111", "cost": "4000$8$4$" }, { "key": "22222222222222222222222222222222", "cost": "4000$8$4$" }]'
attribute_encryption_without_kms: 'true'
available_locales: 'en es fr'
aws_kms_key_id: 'alias/login-dot-gov-development-keymaker'
aws_region: 'us-east-1'
Expand Down Expand Up @@ -256,7 +255,6 @@ production:
attribute_cost: '4000$8$4$' # SCrypt::Engine.calibrate(max_time: 0.5)
attribute_encryption_key: # generate via `rake secret`
attribute_encryption_key_queue: # '[{ "key": "old-key-one", "cost": "4000$8$4$" }, { "key": "old-key-one", "cost": "4000$8$4$" }]'
attribute_encryption_without_kms: 'true'
available_locales: 'en es fr'
aws_kms_key_id:
aws_region:
Expand Down Expand Up @@ -377,7 +375,6 @@ test:
attribute_cost: '800$8$1$' # SCrypt::Engine.calibrate(max_time: 0.01)
attribute_encryption_key: '2086dfbd15f5b0c584f3664422a1d3409a0d2aa6084f65b6ba57d64d4257431c124158670c7655e45cabe64194f7f7b6c7970153c285bdb8287ec0c4f7553e25'
attribute_encryption_key_queue: '[{ "key": "11111111111111111111111111111111", "cost": "4000$8$4$" }, { "key": "22222222222222222222222222222222", "cost": "4000$8$4$" }]'
attribute_encryption_without_kms: 'true'
available_locales: 'en es fr'
aws_kms_key_id: 'alias/login-dot-gov-test-keymaker'
aws_region: 'us-east-1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
it 'renders the show page' do
post :create, params: payload
expect(response).to render_template(:show)
puts flash[:error]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch!

expect(flash[:error]).to eq t('two_factor_authentication.invalid_backup_code')
end
end
Expand Down
13 changes: 2 additions & 11 deletions spec/services/encrypted_attribute_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,16 @@

describe '#stale?' do
it 'returns true when email was encrypted with old key' do
allow(Figaro.env).to receive(:attribute_encryption_without_kms).and_return('false')
encrypted_with_old_key = encrypted_email
rotate_attribute_encryption_key

expect(EncryptedAttribute.new(encrypted_with_old_key).stale?).to eq true
end

it 'returns true with legacy encryption and old key now switched to encryption without kms' do
encrypted_with_old_key = encrypted_email
rotate_attribute_encryption_key
allow(Figaro.env).to receive(:attribute_encryption_without_kms).and_return('true')

expect(EncryptedAttribute.new(encrypted_with_old_key).stale?).to eq true
end

it 'returns false when email was encrypted with current key' do
ee = EncryptedAttribute.new(encrypted_email)
encrypted_with_old_key = EncryptedAttribute.new(encrypted_email)

expect(ee.stale?).to eq false
expect(encrypted_with_old_key.stale?).to eq false
end
end
end
99 changes: 5 additions & 94 deletions spec/services/encryption/encryptors/attribute_encryptor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,91 +16,22 @@
end

describe '#encrypt' do
context 'with old kms based encryption' do
before do
allow(Figaro.env).to receive(:attribute_encryption_without_kms).and_return('false')
end

it 'returns encrypted text' do
ciphertext = subject.encrypt(plaintext)

expect(ciphertext).to_not eq(plaintext)
end
end

context 'with new non kms based encrytpion' do
before do
allow(Figaro.env).to receive(:attribute_encryption_without_kms).and_return('true')
end

it 'returns encrypted text' do
ciphertext = subject.encrypt(plaintext)
it 'returns encrypted text' do
ciphertext = subject.encrypt(plaintext)

expect(ciphertext).to_not eq(plaintext)
end
expect(ciphertext).to_not eq(plaintext)
end
end

describe '#decrypt' do
context 'with old kms based encryption' do
let(:ciphertext) do
subject.encrypt(plaintext)
end

before do
allow(Figaro.env).to receive(:attribute_encryption_without_kms).and_return('false')
# Memoize the ciphertext and purge the key pool so that encryption does not
# affect expected call counts
ciphertext
end

context 'with a ciphertext made with the current key' do
it 'decrypts the ciphertext' do
expect(subject.decrypt(ciphertext)).to eq(plaintext)
end
end

context 'after rotating keys' do
before do
rotate_attribute_encryption_key
end

it 'tries to decrypt with successive keys until it is successful' do
expect(subject.decrypt(ciphertext)).to eq(plaintext)
end
end

context 'it migrates legacy encrypted data after rotating keys' do
before do
rotate_attribute_encryption_key
end

it 'tries to decrypt with successive keys until it is successful' do
expect(subject.decrypt(ciphertext)).to eq(plaintext)
end
end

context 'with a ciphertext made with a key that does not exist' do
before do
rotate_attribute_encryption_key_with_invalid_queue
end

it 'raises and encryption error' do
expect { subject.decrypt(ciphertext) }.to \
raise_error(Encryption::EncryptionError, 'unable to decrypt attribute with any key')
end
end
end

context 'with new new non kms based encryption' do
let(:ciphertext) do
subject.encrypt(plaintext)
end

before do
# Memoize the ciphertext and purge the key pool so that encryption does not
# affect expected call counts
allow(Figaro.env).to receive(:attribute_encryption_without_kms).and_return('true')
# Memoize the ciphertext so that encryption does not affect expected
# call counts
ciphertext
end

Expand All @@ -120,16 +51,6 @@
end
end

context 'it migrates legacy encrypted data after rotating keys' do
before do
rotate_attribute_encryption_key
end

it 'tries to decrypt with successive keys until it is successful' do
expect(subject.decrypt(ciphertext)).to eq(plaintext)
end
end

context 'with a ciphertext made with a key that does not exist' do
before do
rotate_attribute_encryption_key_with_invalid_queue
Expand All @@ -151,19 +72,9 @@
expect(subject.stale?).to eq(false)
end

it 'returns true if an old key was last used to decrypt something' do
allow(Figaro.env).to receive(:attribute_encryption_without_kms).and_return('false')
ciphertext = subject.encrypt(plaintext)
rotate_attribute_encryption_key
subject.decrypt(ciphertext)

expect(subject.stale?).to eq(true)
end

it 'returns true if old key used to decrypt and we turn on new encryption' do
ciphertext = subject.encrypt(plaintext)
rotate_attribute_encryption_key
allow(Figaro.env).to receive(:attribute_encryption_without_kms).and_return('true')
subject.decrypt(ciphertext)

expect(subject.stale?).to eq(true)
Expand Down
Loading