1 module dcrypt.blockcipher.padding.pkcs7;
2 
3 import dcrypt.blockcipher.padding.padding;
4 import dcrypt.random.prng;
5 import dcrypt.exceptions;
6 import std.exception: enforce;
7 
8 /// test PKCS7 padding scheme on a 16 byte block
9 unittest {
10 	PKCS7Pad padding;
11 	ubyte[16] block = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
12 
13 	padding.addPadding(block, 15);
14 	assert(block == [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,1], "PKCS7Padding failed");
15 	assert(padding.padCount(block) == 1, "PKCS7Padding failed");
16 
17 	padding.addPadding(block, 7);
18 	assert(block == [0,1,2,3,4,5,6,9,9,9,9,9,9,9,9,9], "PKCS7Padding failed");
19 	assert(padding.padCount(block) == 9, "PKCS7Padding failed");
20 
21 	padding.addPadding(block, 0);
22 	assert(block == [16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16], "PKCS7Padding failed");
23 	assert(padding.padCount(block) == 16, "PKCS7Padding failed");
24 }
25 
26 static assert(isBlockCipherPadding!PKCS7Pad, "PKCS7Pad violates isBlockCipherPadding.");
27 
28 ///
29 /// PKCS7Pad is an implementation of the PKCS7 block cipher padding scheme.
30 /// A incomplete block will be padded with bytes like this:
31 /// 
32 /// 01
33 /// 02 02
34 /// 03 03 03
35 /// 04 04 04 04
36 /// ...
37 /// 
38 /// The block to be padded can't be full.
39 ///	
40 ///	Standard: rfc5652, http://tools.ietf.org/html/rfc5652#section-6.3
41 /// 
42 /// Example:
43 /// PKCS7Pad pad;
44 /// ubyte[16] block;
45 /// block[0..2] = [1,2];		// block contains 2 bytes
46 /// pad.addPadding(block, 2);	// fill the rest with padding bytes
47 /// assert(pad.padCount(block) == 2);
48 /// 
49 ///
50 @safe
51 public struct PKCS7Pad { 
52 
53 	enum name = "PKCS7Padding";
54 
55 	public {
56 
57 		/**
58 		 * pad with zeros or random bytes if SecureRandom is specified in constructor.
59 		 * Params: block = the block to pad
60 		 * len = the number of data bytes in this block. has to be smaller than the block size.
61 		 */
62 		void addPadding(ubyte[] block, in uint len) pure nothrow @nogc
63 		in{
64 			assert(len < block.length, "len has to be smaller than block size");
65 			assert(block.length < 256, "block to long. can't pad blocks with length > 255");
66 		}
67 		body {
68 			block[len..$] = cast(ubyte) (block.length-len);
69 		}
70 
71 		/**
72 		 * Returns: the number of padding bytes appended to this block.
73 		 * Throws: InvalidCipherTextException if the padding is corrupted.
74 		 */
75 		uint padCount(in ubyte[] block) pure
76 		body {
77 			ubyte len = block[$-1];
78 
79 			enforce(len <= block.length, new InvalidCipherTextException("pad block corrupted"));
80 
81 			foreach(b; block[$-len..$]) {
82 				if(b != len) {
83 					throw  new InvalidCipherTextException("pad block corrupted");
84 				}
85 			}
86 
87 			return len;
88 		}
89 	}
90 }