1 package org.bouncycastle.crypto.digests; 2 3 import org.bouncycastle.util.Arrays; 4 5 /** 6 * Customizable SHAKE function. 7 */ 8 public class CSHAKEDigest 9 extends SHAKEDigest 10 { 11 private static final byte[] padding = new byte[100]; 12 private final byte[] diff; 13 14 /** 15 * Base constructor. 16 * 17 * @param bitLength bit length of the underlying SHAKE function, 128 or 256. 18 * @param N the function name string, note this is reserved for use by NIST. Avoid using it if not required. 19 * @param S the customization string - available for local use. 20 */ CSHAKEDigest(int bitLength, byte[] N, byte[] S)21 public CSHAKEDigest(int bitLength, byte[] N, byte[] S) 22 { 23 super(bitLength); 24 25 if ((N == null || N.length == 0) && (S == null || S.length == 0)) 26 { 27 diff = null; 28 } 29 else 30 { 31 diff = Arrays.concatenate(XofUtils.leftEncode(rate / 8), encodeString(N), encodeString(S)); 32 diffPadAndAbsorb(); 33 } 34 } 35 CSHAKEDigest(CSHAKEDigest source)36 CSHAKEDigest(CSHAKEDigest source) 37 { 38 super(source); 39 40 this.diff = Arrays.clone(source.diff); 41 } 42 43 // bytepad in SP 800-185 diffPadAndAbsorb()44 private void diffPadAndAbsorb() 45 { 46 int blockSize = rate / 8; 47 absorb(diff, 0, diff.length); 48 49 int delta = diff.length % blockSize; 50 51 // only add padding if needed 52 if (delta != 0) 53 { 54 int required = blockSize - delta; 55 56 while (required > padding.length) 57 { 58 absorb(padding, 0, padding.length); 59 required -= padding.length; 60 } 61 62 absorb(padding, 0, required); 63 } 64 } 65 encodeString(byte[] str)66 private byte[] encodeString(byte[] str) 67 { 68 if (str == null || str.length == 0) 69 { 70 return XofUtils.leftEncode(0); 71 } 72 73 return Arrays.concatenate(XofUtils.leftEncode(str.length * 8L), str); 74 } 75 getAlgorithmName()76 public String getAlgorithmName() 77 { 78 return "CSHAKE" + fixedOutputLength; 79 } 80 doOutput(byte[] out, int outOff, int outLen)81 public int doOutput(byte[] out, int outOff, int outLen) 82 { 83 if (diff != null) 84 { 85 if (!squeezing) 86 { 87 absorbBits(0x00, 2); 88 } 89 90 squeeze(out, outOff, ((long)outLen) * 8); 91 92 return outLen; 93 } 94 else 95 { 96 return super.doOutput(out, outOff, outLen); 97 } 98 } 99 reset()100 public void reset() 101 { 102 super.reset(); 103 104 if (diff != null) 105 { 106 diffPadAndAbsorb(); 107 } 108 } 109 } 110