読者です 読者をやめる 読者になる 読者になる

Debuginfo

思考とアウトプット

HashをJSON::XSでシリアライズして、Crypt::CBCで暗号化して、GZIPで圧縮して、それをBSONバイナリとしてMongoDBに保存するPerlコード。またその逆も。

MongoHQの通信はセキュアでありません。なのでhttpsAPIを使って保存するか、もしくはアプリケーション側で暗号化して保存する方法があると思います。今回は後者でコードを書いてみました。

package Util;

use Moo;
use JSON::XS;
use Crypt::CBC;
use IO::Compress::Gzip qw(gzip $GzipError) ;
use IO::Uncompress::Gunzip qw(gunzip $GunzipError) ;
use MongoDB::BSON::Binary;

has cipher => (
    is => 'ro',
    lazy => 1,
    builder => '_build_cipher',
);

has key => (
    is => 'ro',
    required => 1,
);

sub _build_cipher{
    my $self = shift;
    return Crypt::CBC->new({ key => $self->key , cipher => 'Blowfish' });
}

sub serialize {
    my ($self, $hash_or_array) = @_;
    return encode_json $hash_or_array;
}

sub deserialize {
    my ($self, $json_text ) = @_;
    return decode_json $json_text;
}

sub encrypt {
    my ($self, $hash_or_array) = @_;
    my $hex_in = $self->cipher->encrypt_hex( $self->serialize($hash_or_array) );
    my $bin_out;
    gzip \$hex_in => \$bin_out;
    return MongoDB::BSON::Binary->new(data => $bin_out);
}

sub decrypt {
    my ($self, $bin) = @_;
    my $hex_out;
    gunzip \$bin => \$hex_out;
    return $self->deserialize( $self->cipher->decrypt_hex( $hex_out ) );
}

1;

でこれを使って、

!/usr/bin/env perl

use strict;
use warnings;
use FindBin qw($Bin);
use lib "$Bin/../lib";
use Util;
use Data::Dumper;
use MongoDB;

my $hash = { name => "foo" x 3 };
my $util = Util->new(key => "111111111111111111111");
my $bson_bin = $util->encrypt($hash);

#print Dumper $bson_bin;

my $client     = MongoDB::MongoClient->new(
    host => 'localhost', 
    port => 27017, 
    username => "test", 
    password => "test",
    db_name => 'test',
);


my $db = $client->get_database('test');
$db->get_collection('test')->insert({ test_data => $bson_bin });

my $cursor = $db->get_collection('test')->find();
my $a = $cursor->next;

my $text = $util->decrypt($a->{test_data});
print Dumper $text;

これを実行してみるとちゃんと復号もできてる。

$ carton exec --  ./script/test_encrypt.pl                                                                                                
$VAR1 = {
          'name' => 'foofoofoo'
        };

冗長な気もしますが、良しとしましょう。 一つ疑問が。復号できる暗号にストレッチングやソルトを適用した方がいいのでしょうか? 誰か教えてほしい。。