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