@@ -70,7 +70,7 @@ final class P11Cipher extends CipherSpi {
7070 private static interface Padding {
7171 // ENC: format the specified buffer with padding bytes and return the
7272 // actual padding length
73- int setPaddingBytes (byte [] paddingBuffer , int padLen );
73+ int setPaddingBytes (byte [] paddingBuffer , int startOff , int padLen );
7474
7575 // DEC: return the length of trailing padding bytes given the specified
7676 // padded data
@@ -91,8 +91,8 @@ private static class PKCS5Padding implements Padding {
9191 this .blockSize = blockSize ;
9292 }
9393
94- public int setPaddingBytes (byte [] paddingBuffer , int padLen ) {
95- Arrays .fill (paddingBuffer , 0 , padLen , (byte ) (padLen & 0x007f ));
94+ public int setPaddingBytes (byte [] paddingBuffer , int startOff , int padLen ) {
95+ Arrays .fill (paddingBuffer , startOff , startOff + padLen , (byte ) (padLen & 0x007f ));
9696 return padLen ;
9797 }
9898
@@ -169,6 +169,14 @@ public int unpad(byte[] paddedData, int len)
169169 // specification mandates a fixed size of the key
170170 private int fixedKeySize = -1 ;
171171
172+ // Indicates whether the underlying PKCS#11 library requires block-sized
173+ // updates during multi-part operations. In such case, we buffer data in
174+ // padBuffer up to a block-size. This may be needed only if padding is
175+ // applied on the Java side. An example of the previous is when the
176+ // CKM_AES_ECB mechanism is used and the PKCS#11 library is NSS. See more
177+ // on JDK-8261355.
178+ private boolean reqBlockUpdates = false ;
179+
172180 P11Cipher (Token token , String algorithm , long mechanism )
173181 throws PKCS11Exception , NoSuchAlgorithmException {
174182 super ();
@@ -252,6 +260,10 @@ protected void engineSetPadding(String padding)
252260 // no native padding support; use our own padding impl
253261 paddingObj = new PKCS5Padding (blockSize );
254262 padBuffer = new byte [blockSize ];
263+ char [] tokenLabel = token .tokenInfo .label ;
264+ // NSS requires block-sized updates in multi-part operations.
265+ reqBlockUpdates = ((tokenLabel [0 ] == 'N' && tokenLabel [1 ] == 'S'
266+ && tokenLabel [2 ] == 'S' ) ? true : false );
255267 }
256268 } else {
257269 throw new NoSuchPaddingException ("Unsupported padding " + padding );
@@ -587,46 +599,54 @@ private int implUpdate(byte[] in, int inOfs, int inLen,
587599 try {
588600 ensureInitialized ();
589601 int k = 0 ;
590- if (encrypt ) {
591- k = token .p11 .C_EncryptUpdate (session .id (), 0 , in , inOfs , inLen ,
592- 0 , out , outOfs , outLen );
593- } else {
594- int newPadBufferLen = 0 ;
595- if (paddingObj != null ) {
596- if (padBufferLen != 0 ) {
597- // NSS throws up when called with data not in multiple
598- // of blocks. Try to work around this by holding the
599- // extra data in padBuffer.
600- if (padBufferLen != padBuffer .length ) {
601- int bufCapacity = padBuffer .length - padBufferLen ;
602- if (inLen > bufCapacity ) {
603- bufferInputBytes (in , inOfs , bufCapacity );
604- inOfs += bufCapacity ;
605- inLen -= bufCapacity ;
606- } else {
607- bufferInputBytes (in , inOfs , inLen );
608- return 0 ;
609- }
602+ int newPadBufferLen = 0 ;
603+ if (paddingObj != null && (!encrypt || reqBlockUpdates )) {
604+ if (padBufferLen != 0 ) {
605+ if (padBufferLen != padBuffer .length ) {
606+ int bufCapacity = padBuffer .length - padBufferLen ;
607+ if (inLen > bufCapacity ) {
608+ bufferInputBytes (in , inOfs , bufCapacity );
609+ inOfs += bufCapacity ;
610+ inLen -= bufCapacity ;
611+ } else {
612+ bufferInputBytes (in , inOfs , inLen );
613+ return 0 ;
610614 }
615+ }
616+ if (encrypt ) {
617+ k = token .p11 .C_EncryptUpdate (session .id (),
618+ 0 , padBuffer , 0 , padBufferLen ,
619+ 0 , out , outOfs , outLen );
620+ } else {
611621 k = token .p11 .C_DecryptUpdate (session .id (),
612622 0 , padBuffer , 0 , padBufferLen ,
613623 0 , out , outOfs , outLen );
614- padBufferLen = 0 ;
615624 }
616- newPadBufferLen = inLen & (blockSize - 1 );
617- if (newPadBufferLen == 0 ) {
618- newPadBufferLen = padBuffer .length ;
619- }
620- inLen -= newPadBufferLen ;
625+ padBufferLen = 0 ;
626+ }
627+ newPadBufferLen = inLen & (blockSize - 1 );
628+ if (!encrypt && newPadBufferLen == 0 ) {
629+ // While decrypting with implUpdate, the last encrypted block
630+ // is always held in a buffer. If it's the final one (unknown
631+ // at this point), it may contain padding bytes and need further
632+ // processing. In implDoFinal (where we know it's the final one)
633+ // the buffer is decrypted, unpadded and returned.
634+ newPadBufferLen = padBuffer .length ;
621635 }
622- if (inLen > 0 ) {
636+ inLen -= newPadBufferLen ;
637+ }
638+ if (inLen > 0 ) {
639+ if (encrypt ) {
640+ k += token .p11 .C_EncryptUpdate (session .id (), 0 , in , inOfs ,
641+ inLen , 0 , out , (outOfs + k ), (outLen - k ));
642+ } else {
623643 k += token .p11 .C_DecryptUpdate (session .id (), 0 , in , inOfs ,
624644 inLen , 0 , out , (outOfs + k ), (outLen - k ));
625645 }
626- // update 'padBuffer' if using our own padding impl.
627- if ( paddingObj != null ) {
628- bufferInputBytes ( in , inOfs + inLen , newPadBufferLen );
629- }
646+ }
647+ // update 'padBuffer' if using our own padding impl.
648+ if ( paddingObj != null && newPadBufferLen > 0 ) {
649+ bufferInputBytes ( in , inOfs + inLen , newPadBufferLen );
630650 }
631651 bytesBuffered += (inLen - k );
632652 return k ;
@@ -687,60 +707,62 @@ private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)
687707 }
688708
689709 int k = 0 ;
690- if (encrypt ) {
691- if (inAddr == 0 && inArray == null ) {
692- inArray = new byte [inLen ];
693- inBuffer .get (inArray );
694- } else {
695- inBuffer .position (origPos + inLen );
696- }
697- k = token .p11 .C_EncryptUpdate (session .id (),
698- inAddr , inArray , inOfs , inLen ,
699- outAddr , outArray , outOfs , outLen );
700- } else {
701- int newPadBufferLen = 0 ;
702- if (paddingObj != null ) {
703- if (padBufferLen != 0 ) {
704- // NSS throws up when called with data not in multiple
705- // of blocks. Try to work around this by holding the
706- // extra data in padBuffer.
707- if (padBufferLen != padBuffer .length ) {
708- int bufCapacity = padBuffer .length - padBufferLen ;
709- if (inLen > bufCapacity ) {
710- bufferInputBytes (inBuffer , bufCapacity );
711- inOfs += bufCapacity ;
712- inLen -= bufCapacity ;
713- } else {
714- bufferInputBytes (inBuffer , inLen );
715- return 0 ;
716- }
710+ int newPadBufferLen = 0 ;
711+ if (paddingObj != null && (!encrypt || reqBlockUpdates )) {
712+ if (padBufferLen != 0 ) {
713+ if (padBufferLen != padBuffer .length ) {
714+ int bufCapacity = padBuffer .length - padBufferLen ;
715+ if (inLen > bufCapacity ) {
716+ bufferInputBytes (inBuffer , bufCapacity );
717+ inOfs += bufCapacity ;
718+ inLen -= bufCapacity ;
719+ } else {
720+ bufferInputBytes (inBuffer , inLen );
721+ return 0 ;
717722 }
723+ }
724+ if (encrypt ) {
725+ k = token .p11 .C_EncryptUpdate (session .id (), 0 ,
726+ padBuffer , 0 , padBufferLen , outAddr , outArray ,
727+ outOfs , outLen );
728+ } else {
718729 k = token .p11 .C_DecryptUpdate (session .id (), 0 ,
719730 padBuffer , 0 , padBufferLen , outAddr , outArray ,
720731 outOfs , outLen );
721- padBufferLen = 0 ;
722- }
723- newPadBufferLen = inLen & (blockSize - 1 );
724- if (newPadBufferLen == 0 ) {
725- newPadBufferLen = padBuffer .length ;
726732 }
727- inLen -= newPadBufferLen ;
733+ padBufferLen = 0 ;
728734 }
729- if (inLen > 0 ) {
730- if (inAddr == 0 && inArray == null ) {
731- inArray = new byte [inLen ];
732- inBuffer .get (inArray );
733- } else {
734- inBuffer .position (inBuffer .position () + inLen );
735- }
735+ newPadBufferLen = inLen & (blockSize - 1 );
736+ if (!encrypt && newPadBufferLen == 0 ) {
737+ // While decrypting with implUpdate, the last encrypted block
738+ // is always held in a buffer. If it's the final one (unknown
739+ // at this point), it may contain padding bytes and need further
740+ // processing. In implDoFinal (where we know it's the final one)
741+ // the buffer is decrypted, unpadded and returned.
742+ newPadBufferLen = padBuffer .length ;
743+ }
744+ inLen -= newPadBufferLen ;
745+ }
746+ if (inLen > 0 ) {
747+ if (inAddr == 0 && inArray == null ) {
748+ inArray = new byte [inLen ];
749+ inBuffer .get (inArray );
750+ } else {
751+ inBuffer .position (inBuffer .position () + inLen );
752+ }
753+ if (encrypt ) {
754+ k += token .p11 .C_EncryptUpdate (session .id (), inAddr ,
755+ inArray , inOfs , inLen , outAddr , outArray ,
756+ (outOfs + k ), (outLen - k ));
757+ } else {
736758 k += token .p11 .C_DecryptUpdate (session .id (), inAddr ,
737759 inArray , inOfs , inLen , outAddr , outArray ,
738760 (outOfs + k ), (outLen - k ));
739761 }
740- // update 'padBuffer' if using our own padding impl.
741- if ( paddingObj != null && newPadBufferLen != 0 ) {
742- bufferInputBytes ( inBuffer , newPadBufferLen );
743- }
762+ }
763+ // update 'padBuffer' if using our own padding impl.
764+ if ( paddingObj != null && newPadBufferLen > 0 ) {
765+ bufferInputBytes ( inBuffer , newPadBufferLen );
744766 }
745767 bytesBuffered += (inLen - k );
746768 if (!(outBuffer instanceof DirectBuffer ) &&
@@ -779,10 +801,14 @@ private int implDoFinal(byte[] out, int outOfs, int outLen)
779801 int k = 0 ;
780802 if (encrypt ) {
781803 if (paddingObj != null ) {
804+ int startOff = 0 ;
805+ if (reqBlockUpdates ) {
806+ startOff = padBufferLen ;
807+ }
782808 int actualPadLen = paddingObj .setPaddingBytes (padBuffer ,
783- requiredOutLen - bytesBuffered );
809+ startOff , requiredOutLen - bytesBuffered );
784810 k = token .p11 .C_EncryptUpdate (session .id (),
785- 0 , padBuffer , 0 , actualPadLen ,
811+ 0 , padBuffer , 0 , startOff + actualPadLen ,
786812 0 , out , outOfs , outLen );
787813 }
788814 // Some implementations such as the NSS Software Token do not
@@ -863,10 +889,14 @@ private int implDoFinal(ByteBuffer outBuffer)
863889
864890 if (encrypt ) {
865891 if (paddingObj != null ) {
892+ int startOff = 0 ;
893+ if (reqBlockUpdates ) {
894+ startOff = padBufferLen ;
895+ }
866896 int actualPadLen = paddingObj .setPaddingBytes (padBuffer ,
867- requiredOutLen - bytesBuffered );
897+ startOff , requiredOutLen - bytesBuffered );
868898 k = token .p11 .C_EncryptUpdate (session .id (),
869- 0 , padBuffer , 0 , actualPadLen ,
899+ 0 , padBuffer , 0 , startOff + actualPadLen ,
870900 outAddr , outArray , outOfs , outLen );
871901 }
872902 // Some implementations such as the NSS Software Token do not
0 commit comments