- Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathIso7816D4Padding.cs
154 lines (132 loc) · 6.26 KB
/
Iso7816D4Padding.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
usingSystem;
namespaceAlgorithms.Crypto.Paddings;
/// <summary>
/// <para>
/// ISO 7816-4 padding is a padding scheme that is defined in the ISO/IEC 7816-4 documentation.
/// </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>
/// ISO 7816-4 padding works as follows:
/// <para>
/// The first byte of the padding is 0x80, which is the hexadecimal representation of the binary value 10000000. This
/// byte indicates the start of the padding.
/// </para>
/// <para>
/// All other bytes of the padding are 0x00, which is the hexadecimal representation of the binary value 00000000. These
/// bytes fill up the remaining space in the last block.
/// </para>
/// <para>
/// The padding can be of any size, from 1 byte to the block size. For example, if the block size is 8 bytes and the
/// message has 5 bytes, then 3 bytes of padding are needed. The padding would be <c>0x80 0x00 0x00</c>.
/// </para>
/// <para>
/// ISO 7816-4 padding is also known as bit padding,because it simply places a single 1 bit after the plaintext, followed
/// by 0 valued bits up to the block size. It works for both byte-oriented and bit-oriented protocols, as it does not
/// depend on any specific character encoding or representation.
/// </para>
/// </summary>
publicclassIso7816D4Padding:IBlockCipherPadding
{
/// <summary>
/// Adds padding to the input data according to the ISO 7816-4 standard.
/// </summary>
/// <param name="inputData">The input data array that needs padding.</param>
/// <param name="inputOffset">The offset in the input data array where the padding should start.</param>
/// <returns>The number of bytes added as padding.</returns>
/// <exception cref="ArgumentException">
/// Thrown when there is not enough space in the input array for padding or when the input offset is invalid.
/// </exception>
publicintAddPadding(byte[]inputData,intinputOffset)
{
// Calculate the number of padding bytes based on the input data length and offset.
varcode=(byte)(inputData.Length-inputOffset);
// Check if the padding bytes are valid and fit in the input array.
if(code==0||inputOffset+code>inputData.Length)
{
thrownewArgumentException("Not enough space in input array for padding");
}
// Set the first padding byte to 80. This marks the start of padding in the ISO 7816-4 standard.
inputData[inputOffset]=80;
inputOffset++;
// Set the remaining padding bytes to 0.
while(inputOffset<inputData.Length)
{
inputData[inputOffset]=0;
inputOffset++;
}
// Return the number of padding bytes.
returncode;
}
/// <summary>
/// Removes the padding from the input data array and returns the original data.
/// </summary>
/// <param name="inputData">
/// The input data with ISO 7816-4 padding. Must not be null and must have a valid length and padding.
/// </param>
/// <returns>The input data without the padding as a new byte array.</returns>
/// <exception cref="ArgumentException">
/// Thrown when the input data has invalid padding.
/// </exception>
publicbyte[]RemovePadding(byte[]inputData)
{
// Find the index of the first padding byte by scanning from the end of the input.
varpaddingIndex=inputData.Length-1;
// Skip all the padding bytes that are 0.
while(paddingIndex>=0&&inputData[paddingIndex]==0)
{
paddingIndex--;
}
// Check if the first padding byte is 0x80.
if(paddingIndex<0||inputData[paddingIndex]!=0x80)
{
thrownewArgumentException("Invalid padding");
}
// Create a new array to store the unpadded data.
varunpaddedData=newbyte[paddingIndex];
// Copy the unpadded data from the input data to the new array.
Array.Copy(inputData,0,unpaddedData,0,paddingIndex);
// Return the unpadded data array.
returnunpaddedData;
}
/// <summary>
/// Gets the number of padding bytes in the input data according to the ISO 7816-4 standard.
/// </summary>
/// <param name="input">The input data array that has padding.</param>
/// <returns>The number of padding bytes in the input data.</returns>
/// <exception cref="ArgumentException"> Thrown when the input data has invalid padding.</exception>
publicintGetPaddingCount(byte[]input)
{
// Initialize the index of the first padding byte to -1.
varpaddingStartIndex=-1;
// Initialize a mask to indicate if the current byte is still part of the padding.
varstillPaddingMask=-1;
// Initialize the current index to the end of the input data.
varcurrentIndex=input.Length;
// Loop backwards through the input data.
while(--currentIndex>=0)
{
// Get the current byte as an unsigned integer.
varcurrentByte=input[currentIndex]&0xFF;
// Compute a mask to indicate if the current byte is 0x00.
varisZeroMask=(currentByte-1)>>31;
// Compute a mask to indicate if the current byte is 0x80.
varisPaddingStartMask=((currentByte^0x80)-1)>>31;
// Update the index of the first padding byte using bitwise operations.
// If the current byte is 0x80 and still part of the padding, set the index to the current index.
// Otherwise, keep the previous index.
paddingStartIndex^=(currentIndex^paddingStartIndex)&(stillPaddingMask&isPaddingStartMask);
// Update the mask to indicate if the current byte is still part of the padding using bitwise operations.
// If the current byte is 0x00, keep the previous mask.
// Otherwise, set the mask to 0.
stillPaddingMask&=isZeroMask;
}
// Check if the index of the first padding byte is valid.
if(paddingStartIndex<0)
{
thrownewArgumentException("Pad block corrupted");
}
// Return the number of padding bytes.
returninput.Length-paddingStartIndex;
}
}