Avoid allocations when doing encryption with AES-NI

This commit is contained in:
Alex Barney 2019-11-17 10:59:46 -07:00
parent df646fb503
commit 2752a7c3db
16 changed files with 302 additions and 111 deletions

View file

@ -1,6 +1,9 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
#if NETCOREAPP
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
#endif
namespace LibHac.Common namespace LibHac.Common
{ {

View file

@ -1,7 +1,9 @@
using System; // ReSharper disable AssignmentIsFullyDiscarded
using System;
#if HAS_INTRINSICS #if HAS_INTRINSICS
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
using LibHac.Crypto2.Detail;
#endif #endif
namespace LibHac.Crypto2 namespace LibHac.Crypto2
@ -25,7 +27,7 @@ namespace LibHac.Crypto2
#if HAS_INTRINSICS #if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto) if (IsAesNiSupported() && !preferDotNetCrypto)
{ {
return new AesEcbDecryptorHw(key); return new AesEcbDecryptorNi(key);
} }
#endif #endif
return new AesEcbDecryptor(key); return new AesEcbDecryptor(key);
@ -36,7 +38,7 @@ namespace LibHac.Crypto2
#if HAS_INTRINSICS #if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto) if (IsAesNiSupported() && !preferDotNetCrypto)
{ {
return new AesEcbEncryptorHw(key); return new AesEcbEncryptorNi(key);
} }
#endif #endif
return new AesEcbEncryptor(key); return new AesEcbEncryptor(key);
@ -47,7 +49,7 @@ namespace LibHac.Crypto2
#if HAS_INTRINSICS #if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto) if (IsAesNiSupported() && !preferDotNetCrypto)
{ {
return new AesCbcDecryptorHw(key, iv); return new AesCbcDecryptorNi(key, iv);
} }
#endif #endif
return new AesCbcDecryptor(key, iv); return new AesCbcDecryptor(key, iv);
@ -58,7 +60,7 @@ namespace LibHac.Crypto2
#if HAS_INTRINSICS #if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto) if (IsAesNiSupported() && !preferDotNetCrypto)
{ {
return new AesCbcEncryptorHw(key, iv); return new AesCbcEncryptorNi(key, iv);
} }
#endif #endif
return new AesCbcEncryptor(key, iv); return new AesCbcEncryptor(key, iv);
@ -66,6 +68,12 @@ namespace LibHac.Crypto2
public static ICipher CreateCtrDecryptor(ReadOnlySpan<byte> key, ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false) public static ICipher CreateCtrDecryptor(ReadOnlySpan<byte> key, ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false)
{ {
#if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto)
{
return new AesCtrCipherNi(key, iv);
}
#endif
// Encryption and decryption in counter mode is the same operation // Encryption and decryption in counter mode is the same operation
return CreateCtrEncryptor(key, iv, preferDotNetCrypto); return CreateCtrEncryptor(key, iv, preferDotNetCrypto);
} }
@ -75,7 +83,7 @@ namespace LibHac.Crypto2
#if HAS_INTRINSICS #if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto) if (IsAesNiSupported() && !preferDotNetCrypto)
{ {
return new AesCtrEncryptorHw(key, iv); return new AesCtrCipherNi(key, iv);
} }
#endif #endif
return new AesCtrEncryptor(key, iv); return new AesCtrEncryptor(key, iv);
@ -87,7 +95,7 @@ namespace LibHac.Crypto2
#if HAS_INTRINSICS #if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto) if (IsAesNiSupported() && !preferDotNetCrypto)
{ {
return new AesXtsCipherHw(key1, key2, iv, true); return new AesXtsDecryptorNi(key1, key2, iv);
} }
#endif #endif
return new AesXtsCipher(key1, key2, iv, true); return new AesXtsCipher(key1, key2, iv, true);
@ -99,7 +107,7 @@ namespace LibHac.Crypto2
#if HAS_INTRINSICS #if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto) if (IsAesNiSupported() && !preferDotNetCrypto)
{ {
return new AesXtsCipherHw(key1, key2, iv, false); return new AesXtsEncryptorNi(key1, key2, iv);
} }
#endif #endif
return new AesXtsCipher(key1, key2, iv, false); return new AesXtsCipher(key1, key2, iv, false);
@ -108,6 +116,17 @@ namespace LibHac.Crypto2
public static void EncryptEcb128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key, public static void EncryptEcb128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key,
bool preferDotNetCrypto = false) bool preferDotNetCrypto = false)
{ {
#if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto)
{
AesEcbModeNi cipherNi;
unsafe { _ = &cipherNi; } // workaround for CS0165
cipherNi.Initialize(key, false);
cipherNi.Encrypt(input, output);
return;
}
#endif
ICipher cipher = CreateEcbEncryptor(key, preferDotNetCrypto); ICipher cipher = CreateEcbEncryptor(key, preferDotNetCrypto);
cipher.Transform(input, output); cipher.Transform(input, output);
@ -116,6 +135,17 @@ namespace LibHac.Crypto2
public static void DecryptEcb128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key, public static void DecryptEcb128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key,
bool preferDotNetCrypto = false) bool preferDotNetCrypto = false)
{ {
#if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto)
{
AesEcbModeNi cipherNi;
unsafe { _ = &cipherNi; } // workaround for CS0165
cipherNi.Initialize(key, true);
cipherNi.Decrypt(input, output);
return;
}
#endif
ICipher cipher = CreateEcbDecryptor(key, preferDotNetCrypto); ICipher cipher = CreateEcbDecryptor(key, preferDotNetCrypto);
cipher.Transform(input, output); cipher.Transform(input, output);
@ -124,6 +154,17 @@ namespace LibHac.Crypto2
public static void EncryptCbc128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key, public static void EncryptCbc128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key,
ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false) ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false)
{ {
#if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto)
{
AesCbcModeNi cipherNi;
unsafe { _ = &cipherNi; } // workaround for CS0165
cipherNi.Initialize(key, iv, false);
cipherNi.Encrypt(input, output);
return;
}
#endif
ICipher cipher = CreateCbcEncryptor(key, iv, preferDotNetCrypto); ICipher cipher = CreateCbcEncryptor(key, iv, preferDotNetCrypto);
cipher.Transform(input, output); cipher.Transform(input, output);
@ -132,6 +173,17 @@ namespace LibHac.Crypto2
public static void DecryptCbc128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key, public static void DecryptCbc128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key,
ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false) ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false)
{ {
#if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto)
{
AesCbcModeNi cipherNi;
unsafe { _ = &cipherNi; } // workaround for CS0165
cipherNi.Initialize(key, iv, true);
cipherNi.Decrypt(input, output);
return;
}
#endif
ICipher cipher = CreateCbcDecryptor(key, iv, preferDotNetCrypto); ICipher cipher = CreateCbcDecryptor(key, iv, preferDotNetCrypto);
cipher.Transform(input, output); cipher.Transform(input, output);
@ -140,6 +192,17 @@ namespace LibHac.Crypto2
public static void EncryptCtr128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key, public static void EncryptCtr128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key,
ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false) ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false)
{ {
#if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto)
{
AesCtrModeNi cipherNi;
unsafe { _ = &cipherNi; } // workaround for CS0165
cipherNi.Initialize(key, iv);
cipherNi.Transform(input, output);
return;
}
#endif
ICipher cipher = CreateCtrEncryptor(key, iv, preferDotNetCrypto); ICipher cipher = CreateCtrEncryptor(key, iv, preferDotNetCrypto);
cipher.Transform(input, output); cipher.Transform(input, output);
@ -148,6 +211,17 @@ namespace LibHac.Crypto2
public static void DecryptCtr128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key, public static void DecryptCtr128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key,
ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false) ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false)
{ {
#if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto)
{
AesCtrModeNi cipherNi;
unsafe { _ = &cipherNi; } // workaround for CS0165
cipherNi.Initialize(key, iv);
cipherNi.Transform(input, output);
return;
}
#endif
ICipher cipher = CreateCtrDecryptor(key, iv, preferDotNetCrypto); ICipher cipher = CreateCtrDecryptor(key, iv, preferDotNetCrypto);
cipher.Transform(input, output); cipher.Transform(input, output);
@ -156,6 +230,17 @@ namespace LibHac.Crypto2
public static void EncryptXts128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key1, public static void EncryptXts128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key1,
ReadOnlySpan<byte> key2, ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false) ReadOnlySpan<byte> key2, ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false)
{ {
#if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto)
{
AesXtsModeNi cipherNi;
unsafe { _ = &cipherNi; } // workaround for CS0165
cipherNi.Initialize(key1, key2, iv, false);
cipherNi.Encrypt(input, output);
return;
}
#endif
ICipher cipher = CreateXtsEncryptor(key1, key2, iv, preferDotNetCrypto); ICipher cipher = CreateXtsEncryptor(key1, key2, iv, preferDotNetCrypto);
cipher.Transform(input, output); cipher.Transform(input, output);
@ -164,6 +249,17 @@ namespace LibHac.Crypto2
public static void DecryptXts128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key1, public static void DecryptXts128(ReadOnlySpan<byte> input, Span<byte> output, ReadOnlySpan<byte> key1,
ReadOnlySpan<byte> key2, ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false) ReadOnlySpan<byte> key2, ReadOnlySpan<byte> iv, bool preferDotNetCrypto = false)
{ {
#if HAS_INTRINSICS
if (IsAesNiSupported() && !preferDotNetCrypto)
{
AesXtsModeNi cipherNi;
unsafe { _ = &cipherNi; } // workaround for CS0165
cipherNi.Initialize(key1, key2, iv, true);
cipherNi.Decrypt(input, output);
return;
}
#endif
ICipher cipher = CreateXtsDecryptor(key1, key2, iv, preferDotNetCrypto); ICipher cipher = CreateXtsDecryptor(key1, key2, iv, preferDotNetCrypto);
cipher.Transform(input, output); cipher.Transform(input, output);

View file

@ -0,0 +1,39 @@
#if HAS_INTRINSICS
using System;
using LibHac.Crypto2.Detail;
namespace LibHac.Crypto2
{
public struct AesCbcEncryptorNi : ICipher
{
private AesCbcModeNi _baseCipher;
public AesCbcEncryptorNi(ReadOnlySpan<byte> key, ReadOnlySpan<byte> iv)
{
_baseCipher = new AesCbcModeNi();
_baseCipher.Initialize(key, iv, false);
}
public void Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
_baseCipher.Encrypt(input, output);
}
}
public struct AesCbcDecryptorNi : ICipher
{
private AesCbcModeNi _baseCipher;
public AesCbcDecryptorNi(ReadOnlySpan<byte> key, ReadOnlySpan<byte> iv)
{
_baseCipher = new AesCbcModeNi();
_baseCipher.Initialize(key, iv, true);
}
public void Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
_baseCipher.Decrypt(input, output);
}
}
}
#endif

View file

@ -0,0 +1,23 @@
#if HAS_INTRINSICS
using System;
using LibHac.Crypto2.Detail;
namespace LibHac.Crypto2
{
public class AesCtrCipherNi : ICipher
{
private AesCtrModeNi _baseCipher;
public AesCtrCipherNi(ReadOnlySpan<byte> key, ReadOnlySpan<byte> iv)
{
_baseCipher = new AesCtrModeNi();
_baseCipher.Initialize(key, iv);
}
public void Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
_baseCipher.Transform(input, output);
}
}
}
#endif

View file

@ -0,0 +1,39 @@
#if HAS_INTRINSICS
using System;
using LibHac.Crypto2.Detail;
namespace LibHac.Crypto2
{
public class AesEcbEncryptorNi : ICipher
{
private AesEcbModeNi _baseCipher;
public AesEcbEncryptorNi(ReadOnlySpan<byte> key)
{
_baseCipher = new AesEcbModeNi();
_baseCipher.Initialize(key, false);
}
public void Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
_baseCipher.Encrypt(input, output);
}
}
public class AesEcbDecryptorNi : ICipher
{
private AesEcbModeNi _baseCipher;
public AesEcbDecryptorNi(ReadOnlySpan<byte> key)
{
_baseCipher = new AesEcbModeNi();
_baseCipher.Initialize(key, true);
}
public void Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
_baseCipher.Decrypt(input, output);
}
}
}
#endif

View file

@ -1,38 +0,0 @@
#if HAS_INTRINSICS
using System;
namespace LibHac.Crypto2
{
public class AesEcbEncryptorHw : ICipher
{
private AesCoreNi _aesCore;
public AesEcbEncryptorHw(ReadOnlySpan<byte> key)
{
_aesCore = new AesCoreNi();
_aesCore.Initialize(key, false);
}
public void Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
_aesCore.Encrypt(input, output);
}
}
public class AesEcbDecryptorHw : ICipher
{
private AesCoreNi _aesCore;
public AesEcbDecryptorHw(ReadOnlySpan<byte> key)
{
_aesCore = new AesCoreNi();
_aesCore.Initialize(key, true);
}
public void Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
_aesCore.Decrypt(input, output);
}
}
}
#endif

View file

@ -0,0 +1,39 @@
#if HAS_INTRINSICS
using System;
using LibHac.Crypto2.Detail;
namespace LibHac.Crypto2
{
public class AesXtsEncryptorNi : ICipher
{
private AesXtsModeNi _baseCipher;
public AesXtsEncryptorNi(ReadOnlySpan<byte> key1, ReadOnlySpan<byte> key2, ReadOnlySpan<byte> iv)
{
_baseCipher = new AesXtsModeNi();
_baseCipher.Initialize(key1, key2, iv, false);
}
public void Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
_baseCipher.Encrypt(input, output);
}
}
public class AesXtsDecryptorNi : ICipher
{
private AesXtsModeNi _baseCipher;
public AesXtsDecryptorNi(ReadOnlySpan<byte> key1, ReadOnlySpan<byte> key2, ReadOnlySpan<byte> iv)
{
_baseCipher = new AesXtsModeNi();
_baseCipher.Initialize(key1, key2, iv, true);
}
public void Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
_baseCipher.Decrypt(input, output);
}
}
}
#endif

View file

@ -1,28 +1,28 @@
#if HAS_INTRINSICS #if HAS_INTRINSICS
using System; using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
namespace LibHac.Crypto2 namespace LibHac.Crypto2.Detail
{ {
public struct AesCbcEncryptorHw : ICipher public struct AesCbcModeNi
{ {
#pragma warning disable 649
private AesCoreNi _aesCore; private AesCoreNi _aesCore;
#pragma warning restore 649
private Vector128<byte> _iv; private Vector128<byte> _iv;
[MethodImpl(MethodImplOptions.AggressiveOptimization)] public void Initialize(ReadOnlySpan<byte> key, ReadOnlySpan<byte> iv, bool isDecrypting)
public AesCbcEncryptorHw(ReadOnlySpan<byte> key, ReadOnlySpan<byte> iv)
{ {
_aesCore = new AesCoreNi(); _aesCore.Initialize(key, isDecrypting);
_aesCore.Initialize(key, false);
_iv = Unsafe.ReadUnaligned<Vector128<byte>>(ref MemoryMarshal.GetReference(iv)); _iv = Unsafe.ReadUnaligned<Vector128<byte>>(ref MemoryMarshal.GetReference(iv));
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)] public void Encrypt(ReadOnlySpan<byte> input, Span<byte> output)
public void Transform(ReadOnlySpan<byte> input, Span<byte> output)
{ {
int blockCount = Math.Min(input.Length, output.Length) >> 4; int blockCount = Math.Min(input.Length, output.Length) >> 4;
@ -43,24 +43,8 @@ namespace LibHac.Crypto2
_iv = iv; _iv = iv;
} }
}
public struct AesCbcDecryptorHw : ICipher public void Decrypt(ReadOnlySpan<byte> input, Span<byte> output)
{
private AesCoreNi _aesCore;
private Vector128<byte> _iv;
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public AesCbcDecryptorHw(ReadOnlySpan<byte> key, ReadOnlySpan<byte> iv)
{
_aesCore = new AesCoreNi();
_aesCore.Initialize(key, true);
_iv = Unsafe.ReadUnaligned<Vector128<byte>>(ref MemoryMarshal.GetReference(iv));
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public void Transform(ReadOnlySpan<byte> input, Span<byte> output)
{ {
int blockCount = Math.Min(input.Length, output.Length) >> 4; int blockCount = Math.Min(input.Length, output.Length) >> 4;
@ -84,4 +68,4 @@ namespace LibHac.Crypto2
} }
} }
} }
#endif #endif

View file

@ -1,11 +1,11 @@
#if NETCOREAPP #if NETCOREAPP
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
using System;
using System.Runtime.CompilerServices;
namespace LibHac.Crypto2 namespace LibHac.Crypto2.Detail
{ {
[StructLayout(LayoutKind.Sequential, Size = RoundKeyCount * RoundKeySize)] [StructLayout(LayoutKind.Sequential, Size = RoundKeyCount * RoundKeySize)]
public struct AesCoreNi public struct AesCoreNi
@ -15,13 +15,6 @@ namespace LibHac.Crypto2
private Vector128<byte> _roundKeys; private Vector128<byte> _roundKeys;
public AesCoreNi(ReadOnlySpan<byte> key, bool isDecrypting)
{
_roundKeys = default;
KeyExpansion(key, MemoryMarshal.CreateSpan(ref _roundKeys, RoundKeyCount), isDecrypting);
}
public void Initialize(ReadOnlySpan<byte> key, bool isDecrypting) public void Initialize(ReadOnlySpan<byte> key, bool isDecrypting)
{ {
KeyExpansion(key, MemoryMarshal.CreateSpan(ref _roundKeys, RoundKeyCount), isDecrypting); KeyExpansion(key, MemoryMarshal.CreateSpan(ref _roundKeys, RoundKeyCount), isDecrypting);
@ -30,7 +23,6 @@ namespace LibHac.Crypto2
public readonly ReadOnlySpan<Vector128<byte>> RoundKeys => public readonly ReadOnlySpan<Vector128<byte>> RoundKeys =>
MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _roundKeys), RoundKeyCount); MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in _roundKeys), RoundKeyCount);
[MethodImpl(MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.AggressiveOptimization)]
public readonly void Encrypt(ReadOnlySpan<byte> input, Span<byte> output) public readonly void Encrypt(ReadOnlySpan<byte> input, Span<byte> output)
{ {

View file

@ -5,17 +5,18 @@ using System.Runtime.InteropServices;
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
namespace LibHac.Crypto2 namespace LibHac.Crypto2.Detail
{ {
public class AesCtrEncryptorHw : ICipher public struct AesCtrModeNi
{ {
#pragma warning disable 649
private AesCoreNi _aesCore; private AesCoreNi _aesCore;
#pragma warning restore 649
private Vector128<byte> _iv; private Vector128<byte> _iv;
[MethodImpl(MethodImplOptions.AggressiveOptimization)] public void Initialize(ReadOnlySpan<byte> key, ReadOnlySpan<byte> iv)
public AesCtrEncryptorHw(ReadOnlySpan<byte> key, ReadOnlySpan<byte> iv)
{ {
_aesCore = new AesCoreNi();
_aesCore.Initialize(key, false); _aesCore.Initialize(key, false);
_iv = Unsafe.ReadUnaligned<Vector128<byte>>(ref MemoryMarshal.GetReference(iv)); _iv = Unsafe.ReadUnaligned<Vector128<byte>>(ref MemoryMarshal.GetReference(iv));

View file

@ -0,0 +1,28 @@
#if HAS_INTRINSICS
using System;
namespace LibHac.Crypto2.Detail
{
public struct AesEcbModeNi
{
#pragma warning disable 649
private AesCoreNi _aesCore;
#pragma warning restore 649
public void Initialize(ReadOnlySpan<byte> key, bool isDecrypting)
{
_aesCore.Initialize(key, isDecrypting);
}
public void Encrypt(ReadOnlySpan<byte> input, Span<byte> output)
{
_aesCore.Encrypt(input, output);
}
public void Decrypt(ReadOnlySpan<byte> input, Span<byte> output)
{
_aesCore.Decrypt(input, output);
}
}
}
#endif

View file

@ -7,30 +7,27 @@ using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
using LibHac.Common; using LibHac.Common;
namespace LibHac.Crypto2 namespace LibHac.Crypto2.Detail
{ {
public class AesXtsCipherHw : ICipher public struct AesXtsModeNi
{ {
#pragma warning disable 649
private AesCoreNi _dataAesCore; private AesCoreNi _dataAesCore;
private AesCoreNi _tweakAesCore; private AesCoreNi _tweakAesCore;
private Vector128<byte> _iv; #pragma warning restore 649
private bool _decrypting;
public AesXtsCipherHw(ReadOnlySpan<byte> key1, ReadOnlySpan<byte> key2, ReadOnlySpan<byte> iv, bool decrypting) private Vector128<byte> _iv;
public void Initialize(ReadOnlySpan<byte> key1, ReadOnlySpan<byte> key2, ReadOnlySpan<byte> iv, bool decrypting)
{ {
Debug.Assert(key1.Length == AesCrypto.KeySize128); Debug.Assert(key1.Length == AesCrypto.KeySize128);
Debug.Assert(key2.Length == AesCrypto.KeySize128); Debug.Assert(key2.Length == AesCrypto.KeySize128);
Debug.Assert(iv.Length == AesCrypto.KeySize128); Debug.Assert(iv.Length == AesCrypto.KeySize128);
_dataAesCore = new AesCoreNi();
_dataAesCore.Initialize(key1, decrypting); _dataAesCore.Initialize(key1, decrypting);
_tweakAesCore = new AesCoreNi();
_tweakAesCore.Initialize(key2, false); _tweakAesCore.Initialize(key2, false);
_iv = Unsafe.ReadUnaligned<Vector128<byte>>(ref MemoryMarshal.GetReference(iv)); _iv = Unsafe.ReadUnaligned<Vector128<byte>>(ref MemoryMarshal.GetReference(iv));
_decrypting = decrypting;
} }
public void Encrypt(ReadOnlySpan<byte> input, Span<byte> output) public void Encrypt(ReadOnlySpan<byte> input, Span<byte> output)
@ -158,18 +155,6 @@ namespace LibHac.Crypto2
prevOutBlock = Sse2.Xor(tmp, tweak); prevOutBlock = Sse2.Xor(tmp, tweak);
} }
public void Transform(ReadOnlySpan<byte> input, Span<byte> output)
{
if (_decrypting)
{
Decrypt(input, output);
}
else
{
Encrypt(input, output);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector128<byte> Gf128Mul(Vector128<byte> iv, Vector128<byte> mask) private static Vector128<byte> Gf128Mul(Vector128<byte> iv, Vector128<byte> mask)
{ {