2424 */
2525/*
2626 * ===========================================================================
27- * (c) Copyright IBM Corp. 2018, 2021 All Rights Reserved
27+ * (c) Copyright IBM Corp. 2018, 2023 All Rights Reserved
2828 * ===========================================================================
2929 */
3030
3131package com .sun .crypto .provider ;
3232
33- import java .util .Arrays ;
34- import java .io .*;
35- import java .security .*;
36- import javax .crypto .*;
3733import com .sun .crypto .provider .AESCrypt ;
38- import sun .security .jca .JCAUtil ;
39- import sun .security .util .ArrayUtil ;
4034
35+ import java .io .ByteArrayOutputStream ;
36+ import java .io .IOException ;
37+ import java .lang .ref .Cleaner ;
38+ import java .nio .ByteBuffer ;
39+ import java .security .AlgorithmParameters ;
40+ import java .security .InvalidAlgorithmParameterException ;
41+ import java .security .InvalidKeyException ;
42+ import java .security .Key ;
43+ import java .security .MessageDigest ;
44+ import java .security .NoSuchAlgorithmException ;
45+ import java .security .ProviderException ;
46+ import java .security .SecureRandom ;
4147import java .security .spec .AlgorithmParameterSpec ;
4248import java .security .spec .InvalidParameterSpecException ;
43- import java .nio .ByteBuffer ;
44- import jdk .crypto .jniprovider .NativeCrypto ;
49+ import java .util .Arrays ;
4550
46- import sun .nio .ch .DirectBuffer ;
47- import java .lang .invoke .MethodHandles ;
48- import java .lang .invoke .VarHandle ;
49- import java .nio .ByteOrder ;
51+ import javax .crypto .AEADBadTagException ;
52+ import javax .crypto .BadPaddingException ;
53+ import javax .crypto .Cipher ;
54+ import javax .crypto .CipherSpi ;
55+ import javax .crypto .NoSuchPaddingException ;
56+ import javax .crypto .ShortBufferException ;
57+ import javax .crypto .IllegalBlockSizeException ;
5058import javax .crypto .spec .GCMParameterSpec ;
5159
60+ import jdk .crypto .jniprovider .NativeCrypto ;
61+ import jdk .internal .ref .CleanerFactory ;
62+
63+ import sun .security .jca .JCAUtil ;
64+ import sun .security .util .ArrayUtil ;
65+
5266/**
5367 * This class represents ciphers in GaloisCounter (GCM) mode.
5468 *
@@ -68,6 +82,7 @@ abstract class NativeGaloisCounterMode extends CipherSpi {
6882
6983 private byte [] key ;
7084 private boolean encryption = true ;
85+ private final long context ;
7186
7287 private static final int DEFAULT_TAG_LEN = 16 ; // in bytes
7388 private static final int DEFAULT_IV_LEN = 12 ; // in bytes
@@ -97,10 +112,35 @@ abstract class NativeGaloisCounterMode extends CipherSpi {
97112 byte [] lastKey = EMPTY_BUF ;
98113 byte [] lastIv = EMPTY_BUF ;
99114
115+ private boolean newIVLen ;
116+ private boolean newKeyLen ;
117+
100118 byte [] iv ;
101119 SecureRandom random ;
102120
103121 private static final NativeCrypto nativeCrypto = NativeCrypto .getNativeCrypto ();
122+ private static final Cleaner contextCleaner = CleanerFactory .cleaner ();
123+
124+ private static final class GCMCleanerRunnable implements Runnable {
125+ private final long nativeContext ;
126+
127+ public GCMCleanerRunnable (long nativeContext ) {
128+ this .nativeContext = nativeContext ;
129+ }
130+
131+ @ Override
132+ public void run () {
133+ /*
134+ * Release the GCM context.
135+ */
136+ synchronized (NativeGaloisCounterMode .class ) {
137+ long ret = nativeCrypto .DestroyContext (nativeContext );
138+ if (ret == -1 ) {
139+ throw new ProviderException ("Error in destroying context in NativeGaloisCounterMode." );
140+ }
141+ }
142+ }
143+ }
104144
105145 /*
106146 * Constructor
@@ -109,6 +149,12 @@ abstract class NativeGaloisCounterMode extends CipherSpi {
109149 tagLenBytes = DEFAULT_TAG_LEN ;
110150 blockCipher = embeddedCipher ;
111151 this .keySize = keySize ;
152+
153+ context = nativeCrypto .CreateContext ();
154+ if (context == -1 ) {
155+ throw new ProviderException ("Error in creating context for NativeGaloisCounterMode." );
156+ }
157+ contextCleaner .register (this , new GCMCleanerRunnable (context ));
112158 }
113159
114160 /**
@@ -145,6 +191,19 @@ void init(int opmode, Key key, GCMParameterSpec spec)
145191 }
146192 this .key = keyValue .clone ();
147193
194+ /*
195+ * Check whether cipher and IV need to be set,
196+ * whether because something changed here or
197+ * a call to set them in context hasn't been
198+ * made yet.
199+ */
200+ if (lastIv .length != this .iv .length ) {
201+ newIVLen = true ;
202+ }
203+ if (lastKey .length != this .key .length ) {
204+ newKeyLen = true ;
205+ }
206+
148207 // Check for reuse
149208 if (encryption ) {
150209 if (MessageDigest .isEqual (keyValue , lastKey ) &&
@@ -767,17 +826,25 @@ public int doFinal(byte[] in, int inOfs, int inLen, byte[] out,
767826 byte [] aad = ((aadBuffer == null ) || (aadBuffer .size () == 0 )) ? EMPTY_BUF : aadBuffer .toByteArray ();
768827 aadBuffer = null ;
769828
770- ret = nativeCrypto .GCMEncrypt (key , key .length ,
829+ ret = nativeCrypto .GCMEncrypt (context ,
830+ key , key .length ,
771831 iv , iv .length ,
772832 in , inOfs , inLen ,
773833 out , outOfs ,
774- aad , aad .length , localTagLenBytes );
834+ aad , aad .length ,
835+ localTagLenBytes ,
836+ newIVLen ,
837+ newKeyLen );
775838 }
776839
777840 if (ret == -1 ) {
778841 throw new ProviderException ("Error in Native GaloisCounterMode" );
779842 }
780843
844+ /* Cipher and IV length were set, since call to GCMEncrypt succeeded. */
845+ newKeyLen = false ;
846+ newIVLen = false ;
847+
781848 reInit = true ;
782849 return inLen + localTagLenBytes ;
783850 }
@@ -960,17 +1027,27 @@ public int doFinal(byte[] in, int inOfs, int inLen, byte[] out,
9601027 inOfs = 0 ;
9611028 inLen = in .length ;
9621029 ibuffer .reset ();
963- ret = nativeCrypto .GCMDecrypt (key , key .length ,
1030+
1031+ ret = nativeCrypto .GCMDecrypt (context ,
1032+ key , key .length ,
9641033 iv , iv .length ,
9651034 in , inOfs , inLen ,
9661035 out , outOfs ,
967- aad , aad .length , tagLenBytes );
1036+ aad , aad .length ,
1037+ tagLenBytes ,
1038+ newIVLen ,
1039+ newKeyLen );
9681040 }
9691041 if (ret == -2 ) {
9701042 throw new AEADBadTagException ("Tag mismatch!" );
9711043 } else if (ret == -1 ) {
9721044 throw new ProviderException ("Error in Native GaloisCounterMode" );
9731045 }
1046+
1047+ /* Cipher and IV length were set, since call to GCMDecrypt succeeded. */
1048+ newKeyLen = false ;
1049+ newIVLen = false ;
1050+
9741051 return ret ;
9751052 }
9761053
0 commit comments