FFXIVLauncher-Netmaui
93 строки · 3.1 Кб
1// NOTE: This file is copy-pasted almost *as-is* from the previous work `Aither.Crypto`
2// hence currently it does not follow XL's naming convetions.
3//
4// It's totally okay to change this. But for now, this is what it is atm.
5// ReSharper disable InconsistentNaming
6
7using System;
8using System.Buffers.Binary;
9
10namespace XIVLauncher.Common.Encryption.BlockCipher
11{
12public sealed class Blowfish : IBlockCipher
13{
14/// <inheritdoc />
15public int BlockSize => 8;
16
17// NOTE: this field should never be marked as readonly as it actually creates a defensive copy on every access. (it's a trap)
18// https://devblogs.microsoft.com/premier-developer/the-in-modifier-and-the-readonly-structs-in-c/
19
20private BlowfishState m_state;
21
22/// <summary>
23/// Initializes a new instance of the Blowfish class.
24/// </summary>
25/// <remarks>
26/// This function also calculates P-array and S-boxes from the given key. This is most expensive operation in blowfish algorithm.
27/// </remarks>
28/// <param name="key">A secret key used for blowfish. Key length must be between 32 and 448 bits.</param>
29/// <exception cref="ArgumentException">Length of the key is either too short or too long.</exception>
30public Blowfish(ReadOnlySpan<byte> key)
31{
32m_state = new BlowfishState(key);
33}
34
35public unsafe void EncryptBlockUnsafe(byte* input, byte* output)
36{
37var inputBlock = (uint*)input;
38var outputBlock = (uint*)output;
39
40var xl = inputBlock[0];
41var xr = inputBlock[1];
42
43// will be elided by JIT
44if (BitConverter.IsLittleEndian)
45{
46xl = BinaryPrimitives.ReverseEndianness(xl);
47xr = BinaryPrimitives.ReverseEndianness(xr);
48}
49
50(xl, xr) = m_state.EncryptBlock(xl, xr);
51
52// will be elided by JIT
53if (BitConverter.IsLittleEndian)
54{
55xl = BinaryPrimitives.ReverseEndianness(xl);
56xr = BinaryPrimitives.ReverseEndianness(xr);
57}
58
59outputBlock[0] = xl;
60outputBlock[1] = xr;
61}
62
63public unsafe void DecryptBlockUnsafe(byte* input, byte* output)
64{
65var inputBlock = (uint*)input;
66var outputBlock = (uint*)output;
67
68var xl = inputBlock[0];
69var xr = inputBlock[1];
70
71// will be elided by JIT
72if (BitConverter.IsLittleEndian)
73{
74xl = BinaryPrimitives.ReverseEndianness(xl);
75xr = BinaryPrimitives.ReverseEndianness(xr);
76}
77
78(xl, xr) = m_state.DecryptBlock(xl, xr);
79
80// will be elided by JIT
81if (BitConverter.IsLittleEndian)
82{
83xl = BinaryPrimitives.ReverseEndianness(xl);
84xr = BinaryPrimitives.ReverseEndianness(xr);
85}
86
87outputBlock[0] = xl;
88outputBlock[1] = xr;
89}
90}
91}
92
93// ReSharper restore InconsistentNaming
94