1 package org.bouncycastle.crypto.digests;
2 
3 import org.bouncycastle.crypto.Xof;
4 
5 
6 /**
7  * implementation of SHAKE based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
8  * <p>
9  * Following the naming conventions used in the C source code to enable easy review of the implementation.
10  */
11 public class SHAKEDigest
12     extends KeccakDigest
13     implements Xof
14 {
checkBitLength(int bitLength)15     private static int checkBitLength(int bitLength)
16     {
17         switch (bitLength)
18         {
19         case 128:
20         case 256:
21             return bitLength;
22         default:
23             throw new IllegalArgumentException("'bitLength' " + bitLength + " not supported for SHAKE");
24         }
25     }
26 
SHAKEDigest()27     public SHAKEDigest()
28     {
29         this(128);
30     }
31 
SHAKEDigest(int bitLength)32     public SHAKEDigest(int bitLength)
33     {
34         super(checkBitLength(bitLength));
35     }
36 
SHAKEDigest(SHAKEDigest source)37     public SHAKEDigest(SHAKEDigest source) {
38         super(source);
39     }
40 
getAlgorithmName()41     public String getAlgorithmName()
42     {
43         return "SHAKE" + fixedOutputLength;
44     }
45 
getDigestSize()46     public int getDigestSize()
47     {
48         return fixedOutputLength / 4;
49     }
50 
doFinal(byte[] out, int outOff)51     public int doFinal(byte[] out, int outOff)
52     {
53         return doFinal(out, outOff, getDigestSize());
54     }
55 
doFinal(byte[] out, int outOff, int outLen)56     public int doFinal(byte[] out, int outOff, int outLen)
57     {
58         int length = doOutput(out, outOff, outLen);
59 
60         reset();
61 
62         return length;
63     }
64 
doOutput(byte[] out, int outOff, int outLen)65     public int doOutput(byte[] out, int outOff, int outLen)
66     {
67         if (!squeezing)
68         {
69             absorbBits(0x0F, 4);
70         }
71 
72         squeeze(out, outOff, ((long)outLen) * 8);
73 
74         return outLen;
75     }
76 
77     /*
78      * TODO Possible API change to support partial-byte suffixes.
79      */
doFinal(byte[] out, int outOff, byte partialByte, int partialBits)80     protected int doFinal(byte[] out, int outOff, byte partialByte, int partialBits)
81     {
82         return doFinal(out, outOff, getDigestSize(), partialByte, partialBits);
83     }
84 
85     /*
86      * TODO Possible API change to support partial-byte suffixes.
87      */
doFinal(byte[] out, int outOff, int outLen, byte partialByte, int partialBits)88     protected int doFinal(byte[] out, int outOff, int outLen, byte partialByte, int partialBits)
89     {
90         if (partialBits < 0 || partialBits > 7)
91         {
92             throw new IllegalArgumentException("'partialBits' must be in the range [0,7]");
93         }
94 
95         int finalInput = (partialByte & ((1 << partialBits) - 1)) | (0x0F << partialBits);
96         int finalBits = partialBits + 4;
97 
98         if (finalBits >= 8)
99         {
100             absorb((byte)finalInput);
101             finalBits -= 8;
102             finalInput >>>= 8;
103         }
104 
105         if (finalBits > 0)
106         {
107             absorbBits(finalInput, finalBits);
108         }
109 
110         squeeze(out, outOff, ((long)outLen) * 8);
111 
112         reset();
113 
114         return outLen;
115     }
116 }
117