package App::Raps2::Password;

use strict;
use warnings;
use autodie;
use 5.010;

use base 'Exporter';

use Carp 'confess';
use Crypt::CBC;
use Crypt::Eksblowfish;
use Crypt::Eksblowfish::Bcrypt qw(bcrypt_hash en_base64 de_base64);

our @EXPORT_OK = ();
our $VERSION = '0.1';

sub new {
	my ($obj, %conf) = @_;

	$conf{'cost'} //= 12;

	if (not (defined $conf{'salt'} and length($conf{'salt'}) == 16)) {
		confess('incorrect salt length');
	}

	if (not (defined $conf{'passphrase'} and length $conf{'passphrase'})) {
		confess('no passphrase given');
	}

	my $ref = \%conf;

	return bless($ref, $obj);
}

sub salt {
	my ($self, $salt) = @_;

	if (not (defined $salt and length($salt) == 16)) {
		confess('incorrect salt length');
	}

	$self->{'salt'} = $salt;
}

sub encrypt {
	my ($self, $in) = @_;

	my $eksblowfish = Crypt::Eksblowfish->new(
		$self->{'cost'},
		$self->{'salt'},
		$self->{'passphrase'},
	);
	my $cbc = Crypt::CBC->new(-cipher => $eksblowfish);

	return $cbc->encrypt_hex($in);
}

sub decrypt {
	my ($self, $in) = @_;

	my $eksblowfish = Crypt::Eksblowfish->new(
		$self->{'cost'},
		$self->{'salt'},
		$self->{'passphrase'},
	);
	my $cbc = Crypt::CBC->new(-cipher => $eksblowfish);

	return $cbc->decrypt_hex($in);
}

sub crypt {
	my ($self) = @_;

	return en_base64(
		bcrypt_hash({
				key_nul => 1,
				cost => $self->{'cost'},
				salt => $self->{'salt'},
			},
			$self->{'passphrase'},
	));
}

sub verify {
	my ($self, $testhash) = @_;

	my $myhash = $self->crypt();

	if ($testhash eq $myhash) {
		return 1;
	}
	confess('Passwords did not match');
}

1;
