From db80781e7d8404ec736e767b4932cf92501ee022 Mon Sep 17 00:00:00 2001
From: Adil El Farissi <144741970+AdilElFarissi@users.noreply.github.com>
Date: Fri, 23 Feb 2024 21:14:33 +0000
Subject: [PATCH] Basic implementation of AES encryption/decryption and
respective OSSL functions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add methods:
+ private static string AESEncryptString(string secret, string plainText, string ivString= null)
AES Encrypt a string using a password and a random or custom Initialization Vector.
+ private static string AESDecryptString(string secret, string encryptedText, string ivString= null)
AES Decrypt the string encrypted by AESEncryptString with the same password and ivString used in the encryption.
Methods implementations:
+ Util.AESEncrypt(string secret, string plainText)
+ Util.AESDecrypt(string secret, string encryptedText)
+Util.AESEncryptTo(string secret, string plainText, string ivString)
+ Util.AESDecryptFrom(string secret, string encryptedText, string ivString)
OSSL functions as first case of use:
+ osAESEncrypt(string secret, string plainText)
+ osAESDecrypt(string secret, string encryptedText)
+ osAESEncryptTo(string secret, string plainText, string ivString)
+ osAESDecryptFrom(string secret, string encryptedText, string ivString)
LSL script example:
string plainText = "Hello World :)";
string secret = "#!qUeRtY$@123^456€!#";
default
{
touch_start(integer i)
{
string encryptedText = osAESEncrypt(secret, plainText);
llOwnerSay("\nEncrypted with osAESEncrypt:\n"+ encryptedText);
string decryptedText = osAESDecrypt(secret, encryptedText);
llOwnerSay("\nDecrypted with osAESDecrypt:\n"+ decryptedText);
// Encription / Decription with custom Initialization Vector.
string ivString = (string)llGetOwner() /* +"_"+ llGenerateKey() */;
string encryptedToText = osAESEncryptTo(secret, plainText, ivString);
llOwnerSay("\nEncrypted with osAESEncryptTo:\n"+ encryptedToText);
string decryptedFromText = osAESDecryptFrom(secret, encryptedToText, ivString);
llOwnerSay("\nDecrypted with osAESDecryptFrom:\n"+ decryptedFromText);
}
}
Web Rain :)
---
OpenSim/Framework/Util.cs | 111 ++++++++++++++++++
.../Shared/Api/Implementation/OSSL_Api.cs | 60 ++++++++++
.../Shared/Api/Interface/IOSSL_Api.cs | 4 +
.../Shared/Api/Runtime/OSSL_Stub.cs | 24 ++++
bin/ScriptSyntax.xml | 34 ++++++
5 files changed, 233 insertions(+)
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index 8168c1121f..5fa78bbd5f 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -1367,6 +1367,117 @@ namespace OpenSim.Framework
return uuid;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static string AESEncrypt(string secret, string plainText)
+ {
+ return AESEncryptString(secret, plainText, string.Empty);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static string AESEncryptTo(string secret, string plainText, string ivString)
+ {
+ return AESEncryptString(secret, plainText, ivString);
+ }
+ ///
+ /// AES Encrypt a string using a password and a random or custom Initialization
+ /// Vector
+ ///
+ /// The secret encryption password or key.
+ /// The string or text to encrypt.
+ /// (optional) A string used to generate the Initialization Vector eg; an avatarID, a SecureSessionID, an object or script
+ /// ID...
+ /// A string composed by the Initialization Vector bytes and the
+ /// encrypted text bytes converted to lower case HexString and separated by " : "
+ private static string AESEncryptString(string secret, string plainText, string ivString= null)
+ {
+ if(string.IsNullOrEmpty(secret) || string.IsNullOrEmpty(plainText))
+ return string.Empty;
+
+ byte[] iv = string.IsNullOrEmpty(ivString) ? MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(UUID.Random().ToString())) : MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(ivString));
+ byte[] aesKey = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(secret));
+ byte[] encryptedText;
+
+ using (Aes aes = Aes.Create())
+ {
+ aes.Key = aesKey;
+ aes.IV = iv;
+ aes.Mode = CipherMode.CBC;
+ aes.Padding = PaddingMode.PKCS7;
+
+ ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
+ using MemoryStream memoryStream = new();
+ using CryptoStream cryptoStream = new(memoryStream, encryptor, CryptoStreamMode.Write);
+ using (StreamWriter streamWriter = new(cryptoStream))
+ {
+ streamWriter.Write(plainText);
+ streamWriter.Close();
+ }
+
+ encryptedText = memoryStream.ToArray();
+ memoryStream.Dispose();
+ cryptoStream.Dispose();
+ }
+
+ return string.Format("{0}:{1}", Convert.ToHexString(iv), Convert.ToHexString(encryptedText)).ToLower();
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static string AESDecrypt(string secret, string encryptedText)
+ {
+ return AESDecryptString(secret, encryptedText, string.Empty);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static string AESDecryptFrom(string secret, string encryptedText, string ivString)
+ {
+ return AESDecryptString(secret, encryptedText, ivString);
+ }
+
+ ///
+ /// AES Decrypt the string encrypted by AESEncryptString with the same password
+ /// and ivString used in the encryption.
+ ///
+ /// The secret decryption password or key.
+ /// The encrypted string or text.
+ /// The string used to generate the Initialization Vector
+ /// if used in the encription. eg; an avatarID, a SecureSessionID, an object or
+ /// script ID...
+ /// The decrypted string.
+ private static string AESDecryptString(string secret, string encryptedText, string ivString= null)
+ {
+ if(string.IsNullOrEmpty(secret) || string.IsNullOrEmpty(encryptedText))
+ return string.Empty;
+
+ byte[] iv;
+ byte[] buffer;
+ try{
+ iv = string.IsNullOrEmpty(ivString) ? Convert.FromHexString(encryptedText.Split(":")[0].ToUpper()) : MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(ivString));
+ buffer = Convert.FromHexString(encryptedText.Split(":")[1].ToUpper());
+ }catch
+ {
+ return string.Empty;
+ }
+
+ byte[] aesKey = SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(secret));
+
+ using Aes aes = Aes.Create();
+ aes.Key = aesKey;
+ aes.IV = iv;
+ aes.Mode = CipherMode.CBC;
+ aes.Padding = PaddingMode.PKCS7;
+
+ ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
+ using MemoryStream memoryStream = new(buffer);
+ using CryptoStream cryptoStream = new(memoryStream, decryptor, CryptoStreamMode.Read);
+ using StreamReader streamReader = new(cryptoStream);
+
+ string ret = streamReader.ReadToEnd();
+ memoryStream.Dispose();
+ cryptoStream.Dispose();
+ streamReader.Close();
+ return ret;
+ }
+
public static int fast_distance2d(int x, int y)
{
x = Math.Abs(x);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 6306f088fb..c247fe16cb 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -6374,5 +6374,65 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return World.TryGetSceneObjectPart(id, out SceneObjectPart part) ? part.ParentGroup.GetSittingAvatarsCount() : 0;
}
+
+ public LSL_String osAESEncrypt(string secret, string plainText)
+ {
+ if(string.IsNullOrEmpty(secret) || string.IsNullOrEmpty(plainText))
+ return LSL_String.Empty;
+
+ LSL_String ret = Util.AESEncrypt(secret, plainText);
+ if(string.IsNullOrEmpty(ret)){
+ OSSLError("osAESEncrypt: Failed to encrypt!");
+ return LSL_String.Empty;
+ }else
+ {
+ return ret;
+ }
+ }
+
+ public LSL_String osAESDecrypt(string secret, string encryptedText)
+ {
+ if(string.IsNullOrEmpty(secret) || string.IsNullOrEmpty(encryptedText))
+ return LSL_String.Empty;
+
+ LSL_String ret = Util.AESDecrypt(secret, encryptedText);
+ if(string.IsNullOrEmpty(ret)){
+ OSSLError("osAESDecrypt: Failed to Decrypt!");
+ return LSL_String.Empty;
+ }else
+ {
+ return ret;
+ }
+ }
+
+ public LSL_String osAESEncryptTo(string secret, string plainText, string ivString)
+ {
+ if(string.IsNullOrEmpty(secret) || string.IsNullOrEmpty(plainText) || string.IsNullOrEmpty(ivString))
+ return LSL_String.Empty;
+
+ LSL_String ret = Util.AESEncryptTo(secret, plainText, ivString);
+ if(string.IsNullOrEmpty(ret)){
+ OSSLError("osAESEncryptTo: Failed to encrypt!");
+ return LSL_String.Empty;
+ }else
+ {
+ return ret;
+ }
+ }
+
+ public LSL_String osAESDecryptFrom(string secret, string encryptedText, string ivString)
+ {
+ if(string.IsNullOrEmpty(secret) || string.IsNullOrEmpty(encryptedText) || string.IsNullOrEmpty(ivString))
+ return LSL_String.Empty;
+
+ LSL_String ret = Util.AESDecryptFrom(secret, encryptedText, ivString);
+ if(string.IsNullOrEmpty(ret)){
+ OSSLError("osAESDecryptFrom: Failed to decrypt!");
+ return LSL_String.Empty;
+ }else
+ {
+ return ret;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index e4a9ae9607..aaa79c64ee 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -617,5 +617,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
LSL_Integer osGetPrimCount(LSL_Key object_id);
LSL_Integer osGetSittingAvatarsCount();
LSL_Integer osGetSittingAvatarsCount(LSL_Key object_id);
+ LSL_String osAESEncrypt(string secret, string plainText);
+ LSL_String osAESEncryptTo(string secret, string plainText, string ivString);
+ LSL_String osAESDecrypt(string secret, string encryptedText);
+ LSL_String osAESDecryptFrom(string secret, string encryptedText, string ivString);
}
}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
index 046a6d3af1..9f31f80d67 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
@@ -1750,5 +1750,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
return m_OSSL_Functions.osGetSittingAvatarsCount(object_id);
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public LSL_String osAESEncrypt(string secret, string plainText)
+ {
+ return m_OSSL_Functions.osAESEncrypt(secret, plainText);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public LSL_String osAESEncryptTo(string secret, string plainText, string ivString)
+ {
+ return m_OSSL_Functions.osAESEncryptTo(secret, plainText, ivString);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public LSL_String osAESDecrypt(string secret, string encryptedText)
+ {
+ return m_OSSL_Functions.osAESDecrypt(secret, encryptedText);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public LSL_String osAESDecryptFrom(string secret, string encryptedText, string ivString)
+ {
+ return m_OSSL_Functions.osAESDecryptFrom(secret, encryptedText, ivString);
+ }
+
}
}
diff --git a/bin/ScriptSyntax.xml b/bin/ScriptSyntax.xml
index 176432a194..081c063e6f 100644
--- a/bin/ScriptSyntax.xml
+++ b/bin/ScriptSyntax.xml
@@ -8757,5 +8757,39 @@ fc2639fd-5d16-66bf-d8ab-2e4d754c816d
returnstring
arguments
+ osAESEncrypt
+
+ osAESEncryptTo
+
+ returnstring
+ arguments
+ secrettypestring
+ plainTexttypestring
+ ivStringtypestring
+
+
+ osAESDecrypt
+
+ returnstring
+ arguments
+ secrettypestring
+ encryptedTexttypestring
+
+
+ osAESDecryptFrom
+
+ returnstring
+ arguments
+ secrettypestring
+ encryptedTexttypestring
+ ivStringtypestring
+
+
\ No newline at end of file