Аналогичная ситуация возникает в нашей компании, где администраторы баз данных хотят поддерживать между собой пул учетных данных.
Я изначально собирался опубликовать эту идею, но Эриксон побил меня ею . Однако, возможно, стоит написать какой-нибудь псевдокод, чтобы уточнить, поэтому я полагаю, что мое время, отвечающее на вопрос, не напрасно тратится ...
Вещи, которые вам понадобятся:
Прежде всего, давайте настроим схему базы данных. Эти таблицы будут продемонстрированы в ближайшее время.
CREATE TABLE users (
user_id INTEGER,
authentication_hash BINARY,
authentication_salt BINARY,
public_key BINARY,
encrypted_private_key BINARY,
decryption_key_salt BINARY,
PRIMARY KEY(user_id)
)
CREATE TABLE secrets (
secret_id INTEGER,
-- WHATEVER COLUMNS YOU REQUIRE TO ACCURATELY MODEL YOUR PASSWORDS (CLIENT INFO, ETC)
PRIMARY KEY(secret_id)
)
CREATE TABLE granted_secrets (
secret_id INTEGER,
recipient_id INTEGER,
encrypted_data BINARY,
PRIMARY KEY(secret_id, recipient_id),
FOREIGN KEY(secret_id) REFERENCES secrets(secret_id)
FOREIGN KEY(recipient_id) REFERENCES users(user_id)
)
Прежде чем пользователь сможет начать использовать эту систему, он должен быть зарегистрирован.
function register_user(user_id, user_password) {
authentication_salt = generate_random_salt()
authentication_hash = hash(authentication_salt, user_password);
(public_key, private_key) = asymmetric_cipher_generate_random_key_pair();
decryption_key_salt = generate_random_salt()
decryption_key = derive_key(decryption_key_salt, user_password)
encrypted_private_key = symmetric_cipher_encrypt(
input => private_key,
key => decryption_key
)
// IMPORTANT: The decryption_key_hash is never stored
execute("INSERT INTO users (user_id, authentication_hash, authentication_salt, public_key, encrypted_private_key, decryption_key_salt) VALUES (:user_id, :authentication_hash, :authentication_salt, :public_key, :encrypted_private_key, :decryption_key_salt)")
}
Пользователь может войти в систему.
function authenticate_user(user_id, user_password)
correct_authentication_hash = query("SELECT authentication_hash FROM users WHERE user_id = :user_id")
authentication_salt = query("SELECT authentication_salt FROM users WHERE user_id = :user_id")
given_authentication_hash = hash(authentication_salt, user_password)
return correct_authentication_hash == given_authentication_hash
Секрет может быть предоставлен пользователю-получателю.
function grant_secret(secret_id, secret_data, recipient_id) {
recipient_public_key = query("SELECT public_key FROM users WHERE user_id = :recipient_id")
encrypted_secret_data = asymmetric_cipher_encrypt(
input => secret_data,
public_key => recipient_public_key
)
execute("INSERT INTO granted_secrets (secret_id, recipient_id, encrypted_data) VALUES (:secret_id, :recipient_id, :encrypted_secret_data)")
}
Наконец, пользователь, которому был предоставлен доступ к секрету (получатель), может получить его.
void retrieve_secret(secret_id, recipient_id, recipient_password)
encrypted_recipient_private_key = query("SELECT encrypted_private_key FROM users WHERE user_id = :recipient_id")
recipient_decryption_key_salt = query("SELECT decryption_key_salt FROM users WHERE user_id = :recipient_id")
recipient_decryption_key = derive_key(recipient_decryption_key_salt, recipient_password)
recipient_private_key = symmetric_cipher_decrypt(
input => encrypted_recipient_private_key,
key => recipient_decryption_key
)
encrypted_secret_data = query("SELECT encrypted_data FROM granted_secrets WHERE secret_id = :secret_id AND recipient_id = :recipient_id")
secret_data = asymmetric_cipher_decrypt(
input => encrypted_secret_data,
private_key => recipient_private_key
)
return secret_data
Надеюсь, это поможет. Это, безусловно, помогло мне реализовать мои идеи.