1 /*******************************************************************************
2 
3     Miscellaneous cryptographic padding functions
4 
5     Copyright:
6         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
7         All rights reserved.
8 
9     License:
10         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
11         Alternatively, this file may be distributed under the terms of the Tango
12         3-Clause BSD License (see LICENSE_BSD.txt for details).
13 
14 *******************************************************************************/
15 
16 module ocean.util.cipher.misc.Padding;
17 
18 
19 import ocean.meta.types.Qualifiers;
20 import ocean.core.Verify;
21 
22 version (unittest)
23 {
24     import ocean.core.Test;
25 }
26 
27 /*******************************************************************************
28 
29     PKCS#7 padding.
30 
31     Pads the given byte buffer to the given length. The value of the padding
32     byte is the same as the number of bytes added to the buffer, example:
33 
34     A 3-byte buffer with the contents [0xAB, 0xCD, 0xEF] is padded to length 8.
35     The buffer will now contain [0xAB, 0xCD, 0xEF, 0x05, 0x05, 0x05, 0x05, 0x05]
36 
37     PKCS#7 padding is only defined for cases where the number of bytes to be
38     padded is less than 256.
39 
40     Params:
41         buffer = A reference to the buffer to pad
42         pad_len = The length to pad the buffer to
43 
44     Returns:
45         The padded buffer
46 
47 *******************************************************************************/
48 
49 ubyte[] padPKCS7 ( ref ubyte[] buffer, size_t pad_len )
50 {
51     verify(pad_len >= buffer.length);
52     verify(pad_len - buffer.length <= ubyte.max);
53 
54     assumeSafeAppend(buffer);
55 
56     ubyte pad_byte = cast(ubyte)(pad_len - buffer.length);
57 
58     size_t start = buffer.length;
59     buffer.length = pad_len;
60     buffer[start .. $] = pad_byte;
61 
62     return buffer;
63 }
64 
65 unittest
66 {
67     ubyte[] buf0;
68     test!("==")(padPKCS7(buf0, 0), cast(ubyte[])null);
69     test!("==")(padPKCS7(buf0, 1), cast(ubyte[])[1]);
70 
71     auto buf = cast(ubyte[])"YELLOW SUBMARINE".dup;
72     auto padded = padPKCS7(buf, 20);
73     auto expected = cast(ubyte[])"YELLOW SUBMARINE".dup ~ cast(ubyte[])[4, 4, 4, 4];
74     test!("==")(padded, expected);
75 }
76 
77 /*******************************************************************************
78 
79     PKCS#5 padding.
80 
81     Similar to PKCS#7 padding, except PKCS#5 padding is only defined for ciphers
82     that use a block size of 8 bytes. Hence, the given buffer will be padded to
83     a length of 8 bytes.
84 
85     Params:
86         buffer = A reference to the buffer to pad
87 
88     Returns:
89         The padded buffer
90 
91 *******************************************************************************/
92 
93 ubyte[] padPKCS5 ( ref ubyte[] buffer )
94 {
95     verify(buffer.length <= 8);
96 
97     static immutable PKCS5_BLOCK_SIZE = 8;
98     return padPKCS7(buffer, PKCS5_BLOCK_SIZE);
99 }
100 
101 unittest
102 {
103     ubyte[] buf0;
104     test!("==")(padPKCS5(buf0), cast(ubyte[])[8, 8, 8, 8, 8, 8, 8, 8]);
105 
106     auto buf = cast(ubyte[])[0xAB, 0xCD, 0xEF];
107     auto padded = padPKCS5(buf);
108     auto expected = cast(ubyte[])[0xAB, 0xCD, 0xEF, 5, 5, 5, 5, 5];
109     test!("==")(padded, expected);
110 }