forked from sshnet/SSH.NET
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAesCipher.CtrImpl.cs
More file actions
115 lines (96 loc) · 3.95 KB
/
Copy pathAesCipher.CtrImpl.cs
File metadata and controls
115 lines (96 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
using System;
using System.Buffers.Binary;
using System.Numerics;
using System.Security.Cryptography;
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
public partial class AesCipher
{
private sealed class CtrImpl : BlockCipher, IDisposable
{
private readonly Aes _aes;
private readonly ICryptoTransform _encryptor;
private ulong _ivUpper; // The upper 64 bits of the IV
private ulong _ivLower; // The lower 64 bits of the IV
public CtrImpl(
byte[] key,
byte[] iv)
: base(key, 16, mode: null, padding: null)
{
var aes = Aes.Create();
aes.Key = key;
aes.Mode = System.Security.Cryptography.CipherMode.ECB;
aes.Padding = PaddingMode.None;
_aes = aes;
_encryptor = aes.CreateEncryptor();
_ivLower = BinaryPrimitives.ReadUInt64BigEndian(iv.AsSpan(8));
_ivUpper = BinaryPrimitives.ReadUInt64BigEndian(iv);
}
public override byte[] Encrypt(byte[] input, int offset, int length)
{
return CTREncryptDecrypt(input, offset, length);
}
public override byte[] Decrypt(byte[] input, int offset, int length)
{
return CTREncryptDecrypt(input, offset, length);
}
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
throw new NotImplementedException($"Invalid usage of {nameof(DecryptBlock)}.");
}
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
throw new NotImplementedException($"Invalid usage of {nameof(EncryptBlock)}.");
}
private byte[] CTREncryptDecrypt(byte[] data, int offset, int length)
{
var count = length / BlockSize;
if (length % BlockSize != 0)
{
count++;
}
var buffer = new byte[count * BlockSize];
CTRCreateCounterArray(buffer);
_ = _encryptor.TransformBlock(buffer, 0, buffer.Length, buffer, 0);
ArrayXOR(buffer, data, offset, length);
// adjust output for non-blocksized lengths
if (buffer.Length > length)
{
Array.Resize(ref buffer, length);
}
return buffer;
}
// creates the Counter array filled with incrementing copies of IV
private void CTRCreateCounterArray(byte[] buffer)
{
for (var i = 0; i < buffer.Length; i += 16)
{
BinaryPrimitives.WriteUInt64BigEndian(buffer.AsSpan(i + 8), _ivLower);
BinaryPrimitives.WriteUInt64BigEndian(buffer.AsSpan(i), _ivUpper);
_ivLower += 1;
_ivUpper += (_ivLower == 0) ? 1UL : 0UL;
}
}
// XOR 2 arrays using Vector<byte>
private static void ArrayXOR(byte[] buffer, byte[] data, int offset, int length)
{
var i = 0;
var oneVectorFromEnd = length - Vector<byte>.Count;
for (; i <= oneVectorFromEnd; i += Vector<byte>.Count)
{
var v = new Vector<byte>(buffer, i) ^ new Vector<byte>(data, offset + i);
v.CopyTo(buffer, i);
}
for (; i < length; i++)
{
buffer[i] ^= data[offset + i];
}
}
public void Dispose()
{
_aes.Dispose();
_encryptor.Dispose();
}
}
}
}