99import org .bouncycastle .crypto .params .KeyParameter ;
1010import org .bouncycastle .crypto .params .ParametersWithIV ;
1111import org .bouncycastle .util .Arrays ;
12+ import org .bouncycastle .util .Bytes ;
1213import org .bouncycastle .util .Pack ;
1314
1415public class AEAD
1516{
16-
1717 private final short aeadId ;
1818 private final byte [] key ;
1919 private final byte [] baseNonce ;
@@ -32,7 +32,7 @@ public AEAD(short aeadId, byte[] key, byte[] baseNonce)
3232 {
3333 case HPKE .aead_AES_GCM128 :
3434 case HPKE .aead_AES_GCM256 :
35- cipher = new GCMBlockCipher ( new AESEngine ());
35+ cipher = GCMBlockCipher . newInstance ( AESEngine . newInstance ());
3636 break ;
3737 case HPKE .aead_CHACHA20_POLY1305 :
3838 cipher = new ChaCha20Poly1305 ();
@@ -42,106 +42,73 @@ public AEAD(short aeadId, byte[] key, byte[] baseNonce)
4242 }
4343 }
4444
45+ // used by Sender
46+ public byte [] seal (byte [] aad , byte [] pt )
47+ throws InvalidCipherTextException
48+ {
49+ return process (true , aad , pt , 0 , pt .length );
50+ }
4551
4652 // used by Sender
4753 public byte [] seal (byte [] aad , byte [] pt , int ptOffset , int ptLength )
4854 throws InvalidCipherTextException
4955 {
50- if (ptOffset < 0 || ptOffset > pt .length )
51- {
52- throw new IndexOutOfBoundsException ("Invalid offset" );
53- }
54- if (ptOffset + ptLength > pt .length )
55- {
56- throw new IndexOutOfBoundsException ("Invalid length" );
57- }
58-
59- CipherParameters params ;
60- switch (aeadId )
61- {
62- case HPKE .aead_AES_GCM128 :
63- case HPKE .aead_AES_GCM256 :
64- case HPKE .aead_CHACHA20_POLY1305 :
65- params = new ParametersWithIV (new KeyParameter (key ), ComputeNonce ());
66- break ;
67- case HPKE .aead_EXPORT_ONLY :
68- default :
69- throw new IllegalStateException ("Export only mode, cannot be used to seal/open" );
70- }
71- cipher .init (true , params );
72- cipher .processAADBytes (aad , 0 , aad .length );
73- byte [] ct = new byte [cipher .getOutputSize (ptLength )];
74- int len = cipher .processBytes (pt , ptOffset , ptLength , ct , 0 );
75- cipher .doFinal (ct , len );
56+ Arrays .validateSegment (pt , ptOffset , ptLength );
7657
77- seq ++;
78- return ct ;
58+ return process (true , aad , pt , ptOffset , ptLength );
7959 }
8060
81- // used by Sender
82- public byte [] seal (byte [] aad , byte [] pt )
61+ // used by Receiver
62+ public byte [] open (byte [] aad , byte [] ct )
8363 throws InvalidCipherTextException
8464 {
85- return this . seal ( aad , pt , 0 , pt .length );
65+ return process ( false , aad , ct , 0 , ct .length );
8666 }
8767
8868 // used by Receiver
8969 public byte [] open (byte [] aad , byte [] ct , int ctOffset , int ctLength )
9070 throws InvalidCipherTextException
9171 {
92- if (ctOffset < 0 || ctOffset > ct .length )
93- {
94- throw new IndexOutOfBoundsException ("Invalid offset" );
95- }
96- if (ctOffset + ctLength > ct .length )
97- {
98- throw new IndexOutOfBoundsException ("Invalid length" );
99- }
72+ Arrays .validateSegment (ct , ctOffset , ctLength );
73+
74+ return process (false , aad , ct , ctOffset , ctLength );
75+ }
76+
77+ private byte [] computeNonce ()
78+ {
79+ byte [] seq_bytes = Pack .longToBigEndian (seq ++);
80+ byte [] nonce = Arrays .clone (baseNonce );
81+ Bytes .xorTo (8 , seq_bytes , 0 , nonce , nonce .length - 8 );
82+ return nonce ;
83+ }
10084
85+ private byte [] process (boolean forEncryption , byte [] aad , byte [] buf , int off , int len )
86+ throws InvalidCipherTextException
87+ {
10188 CipherParameters params ;
10289 switch (aeadId )
10390 {
10491 case HPKE .aead_AES_GCM128 :
10592 case HPKE .aead_AES_GCM256 :
10693 case HPKE .aead_CHACHA20_POLY1305 :
107- params = new ParametersWithIV (new KeyParameter (key ), ComputeNonce ());
94+ params = new ParametersWithIV (new KeyParameter (key ), computeNonce ());
10895 break ;
10996 case HPKE .aead_EXPORT_ONLY :
11097 default :
11198 throw new IllegalStateException ("Export only mode, cannot be used to seal/open" );
11299 }
113100
114- cipher .init (false , params );
101+ cipher .init (forEncryption , params );
115102 cipher .processAADBytes (aad , 0 , aad .length );
116103
117- byte [] pt = new byte [cipher .getOutputSize (ctLength )];
118- int len = cipher .processBytes (ct , ctOffset , ctLength , pt , 0 );
119- len += cipher .doFinal (pt , len );
120-
121- seq ++;
122- return pt ;
123- }
124-
125- // used by Receiver
126- public byte [] open (byte [] aad , byte [] ct )
127- throws InvalidCipherTextException
128- {
129- return this .open (aad , ct , 0 , ct .length );
130- }
131-
132- private byte [] ComputeNonce ()
133- {
134- byte [] seq_bytes = Pack .longToBigEndian (seq );
135- int Nn = baseNonce .length ;
136- byte [] nonce = Arrays .clone (baseNonce );
137- //xor
138- for (int i = 0 ; i < 8 ; i ++)
104+ byte [] output = new byte [cipher .getOutputSize (len )];
105+ int pos = cipher .processBytes (buf , off , len , output , 0 );
106+ pos += cipher .doFinal (output , pos );
107+ if (pos != output .length )
139108 {
140- nonce [Nn - 8 + i ] ^= seq_bytes [i ];
109+ // Existing AEAD modes should return exact value for getOutputSize.
110+ throw new IllegalStateException ();
141111 }
142- return nonce ;
112+ return output ;
143113 }
144-
145-
146114}
147-
0 commit comments