- Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathTbcPadding.cs
161 lines (137 loc) · 6.07 KB
/
TbcPadding.cs
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
usingSystem;
namespaceAlgorithms.Crypto.Paddings;
/// <summary>
/// <para>
/// Trailing-Bit-Complement padding is a padding scheme that is defined in the ISO/IEC 9797-1 standard.
/// </para>
/// <para>
/// It is used for adding data to the end of a message that needs to be encrypted or decrypted by a block cipher.
/// </para>
/// <para>
/// The padding bytes are either 0x00 or 0xFF, depending on the last bit of the original data. For example, if the last
/// bit of the original data is 0, then the padding bytes are 0xFF; if the last bit is 1, then the padding bytes are 0x00.
/// The padding bytes are added at the end of the data block until the desired length is reached.
/// </para>
/// </summary>
publicclassTbcPadding:IBlockCipherPadding
{
/// <summary>
/// Adds padding to the input array according to the TBC standard.
/// </summary>
/// <param name="input">The input array to be padded.</param>
/// <param name="inputOffset">The offset in the input array where the padding starts.</param>
/// <returns>The number of bytes that were added.</returns>
/// <exception cref="ArgumentException">Thrown when the input array does not have enough space for padding.</exception>
publicintAddPadding(byte[]input,intinputOffset)
{
// Calculate the number of bytes to be padded.
varcount=input.Length-inputOffset;
bytecode;
// Check if the input array has enough space for padding.
if(count<0)
{
thrownewArgumentException("Not enough space in input array for padding");
}
if(inputOffset>0)
{
// Get the last bit of the previous byte.
varlastBit=input[inputOffset-1]&0x01;
// Set the padding code to 0xFF if the last bit is 0, or 0x00 if the last bit is 1.
code=(byte)(lastBit==0?0xff:0x00);
}
else
{
// Get the last bit of the last byte in the input array.
varlastBit=input[^1]&0x01;
// Set the padding code to 0xff if the last bit is 0, or 0x00 if the last bit is 1.
code=(byte)(lastBit==0?0xff:0x00);
}
while(inputOffset<input.Length)
{
// Set each byte to the padding code.
input[inputOffset]=code;
inputOffset++;
}
// Return the number of bytes that were padded.
returncount;
}
/// <summary>
/// Removes the padding from a byte array according to the Trailing-Bit-Complement padding algorithm.
/// </summary>
/// <param name="input">The byte array to remove the padding from.</param>
/// <returns>A new byte array without the padding.</returns>
/// <remarks>
/// This method assumes that the input array has padded with either 0x00 or 0xFF bytes, depending on the last bit of
/// the original data. The method works by finding the last byte that does not match the padding code and copying all
/// the bytes up to that point into a new array. If the input array is not padded or has an invalid padding, the
/// method may return incorrect results.
/// </remarks>
publicbyte[]RemovePadding(byte[]input)
{
if(input.Length==0)
{
returnArray.Empty<byte>();
}
// Get the last byte of the input array.
varlastByte=input[^1];
// Determine the byte code
varcode=(byte)((lastByte&0x01)==0?0x00:0xff);
// Start from the end of the array and move towards the front.
inti;
for(i=input.Length-1;i>=0;i--)
{
// If the current byte does not match the padding code, stop.
if(input[i]!=code)
{
break;
}
}
// Create a new array of the appropriate length.
varunpadded=newbyte[i+1];
// Copy the unpadded data into the new array.
Array.Copy(input,unpadded,i+1);
// Return the new array.
returnunpadded;
}
/// <summary>
/// Returns the number of padding bytes in a byte array according to the Trailing-Bit-Complement padding algorithm.
/// </summary>
/// <param name="input">The byte array to check for padding.</param>
/// <returns>The number of padding bytes in the input array.</returns>
/// <remarks>
/// This method assumes that the input array has been padded with either 0x00 or 0xFF bytes, depending on the last
/// bit of the original data. The method works by iterating backwards from the end of the array and counting the
/// number of bytes that match the padding code. The method uses bitwise operations to optimize the performance and
/// avoid branching. If the input array is not padded or has an invalid padding, the method may return incorrect
/// results.
/// </remarks>
publicintGetPaddingCount(byte[]input)
{
varlength=input.Length;
if(length==0)
{
thrownewArgumentException("No padding found.");
}
// Get the value of the last byte as the padding value
varpaddingValue=input[--length]&0xFF;
varpaddingCount=1;// Start count at 1 for the last byte
varcountingMask=-1;// Initialize counting mask
// Check if there is no padding
if(paddingValue!=0&&paddingValue!=0xFF)
{
thrownewArgumentException("No padding found");
}
// Loop backwards through the array
for(vari=length-1;i>=0;i--)
{
varcurrentByte=input[i]&0xFF;
// Calculate matchMask. If currentByte equals paddingValue, matchMask will be 0, otherwise -1
varmatchMask=((currentByte^paddingValue)-1)>>31;
// Update countingMask. Once a non-matching byte is found, countingMask will remain -1
countingMask&=matchMask;
// Increment count only if countingMask is 0 (i.e., currentByte matches paddingValue)
paddingCount-=countingMask;
}
returnpaddingCount;
}
}