@@ -42,6 +42,8 @@ public class HmacOneTimePasswordGenerator {
4242
4343 private final int modDivisor ;
4444
45+ private final ThreadLocal <Mac > macThreadLocal ;
46+
4547 /**
4648 * The default length, in decimal digits, for one-time passwords.
4749 */
@@ -118,6 +120,16 @@ protected HmacOneTimePasswordGenerator(final int passwordLength, final String al
118120 // Our purpose here is just to throw an exception immediately if the algorithm is bogus.
119121 Mac .getInstance (algorithm );
120122 this .algorithm = algorithm ;
123+
124+ this .macThreadLocal = ThreadLocal .withInitial (() -> {
125+ try {
126+ return Mac .getInstance (algorithm );
127+ } catch (final NoSuchAlgorithmException e ) {
128+ // This should never happen; we just checked to make sure we could instantiate a MAC with this
129+ // algorithm, and if we made it this far, we know it worked.
130+ throw new RuntimeException (e );
131+ }
132+ });
121133 }
122134
123135 /**
@@ -132,15 +144,8 @@ protected HmacOneTimePasswordGenerator(final int passwordLength, final String al
132144 * @throws InvalidKeyException if the given key is inappropriate for initializing the {@link Mac} for this generator
133145 */
134146 public int generateOneTimePassword (final Key key , final long counter ) throws InvalidKeyException {
135- final Mac mac ;
136-
137- try {
138- mac = Mac .getInstance (this .algorithm );
139- mac .init (key );
140- } catch (final NoSuchAlgorithmException e ) {
141- // This should never happen since we verify that the algorithm is legit in the constructor.
142- throw new RuntimeException (e );
143- }
147+ final Mac mac = this .macThreadLocal .get ();
148+ mac .init (key );
144149
145150 final ByteBuffer buffer = ByteBuffer .allocate (8 );
146151 buffer .putLong (0 , counter );
0 commit comments