/*
* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.Accounts
* File: RsaClientDataEncryption.cs
*
* RsaClientDataEncryption.cs is part of VNLib.Plugins.Essentials.Accounts
* which is part of the larger VNLib collection of libraries and utilities.
*
* VNLib.Plugins.Essentials.Accounts is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* VNLib.Plugins.Essentials.Accounts is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
using System;
using System.Security.Cryptography;
using VNLib.Utils;
using VNLib.Utils.Memory;
namespace VNLib.Plugins.Essentials.Accounts.SecurityProvider
{
internal static class RsaClientDataEncryption
{
///
/// The client data encryption padding. Client library must match this padding
///
public static readonly RSAEncryptionPadding ClientEncryptonPadding = RSAEncryptionPadding.OaepSHA256;
///
/// Tries to encrypt the specified data using the specified public key
///
/// A base64 encoded public key used to encrypt client data
/// Data to encrypt
/// The buffer to store encrypted data in
///
/// The number of encrypted bytes written to the output buffer,
/// or false (0) if the operation failed, or if no credential is
/// specified.
///
///
public static ERRNO TryEncrypt(ReadOnlySpan base64PubKey, ReadOnlySpan data, Span outputBuffer)
{
if (base64PubKey.IsEmpty)
{
return ERRNO.E_FAIL;
}
//Alloc a buffer for decoding the public key
using UnsafeMemoryHandle pubKeyBuffer = MemoryUtil.UnsafeAllocNearestPage(base64PubKey.Length, true);
//Decode the public key
ERRNO pbkBytesWritten = VnEncoding.TryFromBase64Chars(base64PubKey, pubKeyBuffer.Span);
//Try to encrypt the data
return pbkBytesWritten ? TryEncrypt(pubKeyBuffer.Span[..(int)pbkBytesWritten], data, outputBuffer) : ERRNO.E_FAIL;
}
///
/// Tries to encrypt the specified data using the specified public key
///
/// The raw SKI public key
/// Data to encrypt
/// The buffer to store encrypted data in
///
/// The number of encrypted bytes written to the output buffer,
/// or false (0) if the operation failed, or if no credential is
/// specified.
///
///
public static ERRNO TryEncrypt(ReadOnlySpan rawPubKey, ReadOnlySpan data, Span outputBuffer)
{
if (rawPubKey.IsEmpty)
{
return false;
}
//Setup new empty rsa
using RSA rsa = RSA.Create();
//Import the public key
rsa.ImportSubjectPublicKeyInfo(rawPubKey, out _);
//Encrypt data with OaepSha256 as configured in the browser
return rsa.TryEncrypt(data, outputBuffer, ClientEncryptonPadding, out int bytesWritten) ? bytesWritten : ERRNO.E_FAIL;
}
}
}