Bivio::Type::PasswordHashBase
# Copyright (c) 2023 bivio Software, Inc. All rights reserved. package Bivio::Type::PasswordHashBase; use strict; use Bivio::Base 'Type.SyntacticString'; my($_IDI) = __PACKAGE__->instance_data_index; my(@_SALT_CHARS) = ( 'a'..'z', 'A'..'Z', '0'..'9', ); my($_SALT_INDEX_MAX) = int(@_SALT_CHARS) - 1; sub ID { b_die('abstract method'); } sub REGEX { b_die('abstract method'); } sub SALT_LENGTH { b_die('abstract method'); } sub as_literal { my($self) = @_; return $self->internal_format_literal($self->get_salt, $self->get_hash); } sub compare { my($self, $clear_text) = @_; return $self->as_literal cmp $self->to_literal($clear_text, $self->get_salt); } sub get_id { return shift->[$_IDI]{id}; } sub get_salt { return shift->[$_IDI]{salt}; } sub get_hash { return shift->[$_IDI]{hash}; } sub internal_format_literal { my($proto, $salt, $hash) = @_; return '$' . join('$', $proto->ID, $salt, $hash); } sub internal_post_from_literal { my($proto, $value) = @_; my($self) = $proto->SUPER::new; $self->[$_IDI] = $proto->internal_to_parts($value); return $self; } sub internal_random_salt { my($proto) = @_; my($salt) = ''; for (my($i) = 0; $i < $proto->SALT_LENGTH; $i++) { $salt .= $_SALT_CHARS[int(rand($_SALT_INDEX_MAX) + 0.5)]; }; return $salt; } sub internal_to_literal { b_die('abstract method'); } sub internal_to_parts { my($proto, $value) = @_; my($id, $salt, $hash) = split('\$', substr($value, 1)); return { id => $id, salt => $salt, hash => $hash, }; } sub to_literal { my($proto, $clear_text, $salt) = @_; $salt ||= $proto->internal_random_salt; return $proto->internal_to_literal($clear_text, $salt); } 1;