/* * 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; } } }