VYPR
Medium severityGHSA Advisory· Published Oct 24, 2025· Updated Apr 15, 2026

CVE-2025-12194

CVE-2025-12194

Description

Uncontrolled Resource Consumption vulnerability in Legion of the Bouncy Castle Inc. Bouncy Castle for Java FIPS bc-fips on All (API modules), Legion of the Bouncy Castle Inc. Bouncy Castle for Java LTS bcprov-lts8on on All (API modules) allows Excessive Allocation. This vulnerability is associated with program files core/src/main/jdk1.9/org/bouncycastle/crypto/fips/AESNativeCFB.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/fips/AESNativeGCM.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/fips/SHA256NativeDigest.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/fips/AESNativeEngine.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/fips/AESNativeCBC.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/fips/AESNativeCTR.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeCFB.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeGCM.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeEngine.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeCBC.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeGCMSIV.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeCCM.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeCTR.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/digests/SHA256NativeDigest.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/digests/SHA224NativeDigest.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/digests/SHA3NativeDigest.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/digests/SHAKENativeDigest.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/digests/SHA512NativeDigest.Java, core/src/main/jdk1.9/org/bouncycastle/crypto/digests/SHA384NativeDigest.Java.

This issue affects Bouncy Castle for Java FIPS: from 2.1.0 through 2.1.1; Bouncy Castle for Java LTS: from 2.73.0 through 2.73.7.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.bouncycastle:bc-fipsMaven
>= 2.1.0, < 2.1.22.1.2
org.bouncycastle:bcprov-debug-lts8onMaven
>= 2.73.0, < 2.73.82.73.8

Affected products

1

Patches

2
2c9be6c64152

mv java9 to jdk1.9

https://github.com/bcgit/bc-lts-javaDavid HookAug 27, 2025via ghsa
16 files changed · +4 4
  • core/build.gradle+2 2 modified
    @@ -10,7 +10,7 @@ jar.archiveBaseName = "bccore-lts$vm_range"
     sourceSets {
         java9 {
             java {
    -            srcDirs = ['src/main/java9']
    +            srcDirs = ['src/main/jdk1.9']
             }
         }
     }
    @@ -97,7 +97,7 @@ compileJava9Java {
             languageVersion = JavaLanguageVersion.of(11)
         }
         options.release = 9
    -    options.sourcepath = files(['src/main/java', 'src/main/java9'])
    +    options.sourcepath = files(['src/main/java', 'src/main/jdk1.9'])
     }
     
     
    
  • core/src/main/jdk1.9/module-info.java+0 0 renamed
  • core/src/main/jdk1.9/org/bouncycastle/crypto/digests/SHA224NativeDigest.java+0 0 renamed
  • core/src/main/jdk1.9/org/bouncycastle/crypto/digests/SHA256NativeDigest.java+0 0 renamed
  • core/src/main/jdk1.9/org/bouncycastle/crypto/digests/SHA384NativeDigest.java+0 0 renamed
  • core/src/main/jdk1.9/org/bouncycastle/crypto/digests/SHA3NativeDigest.java+0 0 renamed
  • core/src/main/jdk1.9/org/bouncycastle/crypto/digests/SHA512NativeDigest.java+0 0 renamed
  • core/src/main/jdk1.9/org/bouncycastle/crypto/digests/SHAKENativeDigest.java+0 0 renamed
  • core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeCBC.java+0 0 renamed
  • core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeCCM.java+0 0 renamed
  • core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeCFB.java+0 0 renamed
  • core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeCTR.java+0 0 renamed
  • core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeEngine.java+0 0 renamed
  • core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeGCM.java+0 0 renamed
  • core/src/main/jdk1.9/org/bouncycastle/crypto/engines/AESNativeGCMSIV.java+0 0 renamed
  • prov/build.gradle+2 2 modified
    @@ -17,7 +17,7 @@ sourceSets {
         }
         java9 {
             java {
    -            srcDirs = ['src/main/jdk1.9','../core/src/main/java9/org']
    +            srcDirs = ['src/main/jdk1.9','../core/src/main/jdk1.9/org']
             }
         }
         java11 {
    @@ -64,7 +64,7 @@ compileJava {
     compileJava9Java {
         options.release = 9
         options.debug = rootProject.ext.debugBuild
    -    options.sourcepath = files(['../core/src/main/java', 'src/main/java', 'src/main/jdk1.9','../core/src/main/java9/org'])
    +    options.sourcepath = files(['../core/src/main/java', 'src/main/java', 'src/main/jdk1.9','../core/src/main/jdk1.9/org'])
     }
     
     compileJava11Java {
    
f2776feac0c3

Initial:

https://github.com/bcgit/bc-lts-javamwcwAug 20, 2025via ghsa
33 files changed · +5612 818
  • core/build.gradle+23 0 modified
    @@ -6,8 +6,22 @@ plugins {
     
     jar.archiveBaseName = "bccore-lts$vm_range"
     
    +
    +sourceSets {
    +    java9 {
    +        java {
    +            srcDirs = ['src/main/java9']
    +        }
    +    }
    +}
    +
    +
     dependencies {
       testImplementation 'com.fasterxml.jackson.core:jackson-databind:2.13.3'
    +
    +    java9Implementation files([sourceSets.main.output.classesDirs]) {
    +        builtBy compileJava
    +    }
     }
     
     test {
    @@ -68,6 +82,15 @@ artifacts {
     }
     
     
    +compileJava9Java {
    +    javaCompiler = javaToolchains.compilerFor {
    +        languageVersion = JavaLanguageVersion.of(11)
    +    }
    +    options.release = 9
    +    options.sourcepath = files(['src/main/java', 'src/main/java9'])
    +}
    +
    +
     task cleanNative(type: Delete) {
         delete("$projectDir/src/main/resources/native/");
         delete("$projectDir/src/main/resources/META-INF/DRIVERS");
    
  • core/src/main/java9/org/bouncycastle/crypto/digests/SHA224NativeDigest.java+269 0 added
    @@ -0,0 +1,269 @@
    +package org.bouncycastle.crypto.digests;
    +
    +import org.bouncycastle.crypto.CryptoServiceProperties;
    +import org.bouncycastle.crypto.CryptoServicePurpose;
    +import org.bouncycastle.crypto.CryptoServicesRegistrar;
    +import org.bouncycastle.crypto.SavableDigest;
    +import org.bouncycastle.util.Memoable;
    +import org.bouncycastle.util.dispose.NativeDisposer;
    +import org.bouncycastle.util.dispose.NativeReference;
    +
    +import java.lang.ref.Reference;
    +
    +/**
    + * SHA224 implementation.
    + */
    +class SHA224NativeDigest
    +        implements SavableDigest
    +{
    +    private final CryptoServicePurpose purpose;
    +
    +    protected DigestRefWrapper nativeRef = null;
    +
    +    SHA224NativeDigest(CryptoServicePurpose purpose)
    +    {
    +        this.purpose = purpose;
    +        nativeRef = new DigestRefWrapper(makeNative());
    +        reset();
    +        CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
    +    }
    +
    +    SHA224NativeDigest()
    +    {
    +        this(CryptoServicePurpose.ANY);
    +    }
    +
    +    SHA224NativeDigest(SHA224NativeDigest src)
    +    {
    +
    +        this(CryptoServicePurpose.ANY);
    +
    +        byte[] state = src.getEncodedState();
    +
    +        restoreFullState(nativeRef.getReference(), state, 0);
    +    }
    +
    +    //
    +    // From BC-LTS, used for testing in FIPS api only.
    +    // ----------------------- Start Testing only methods.
    +
    +    SHA224NativeDigest restoreState(byte[] state, int offset)
    +    {
    +        restoreFullState(nativeRef.getReference(), state, offset);
    +        return this;
    +    }
    +
    +    //
    +    // ----------------------- End Testing only methods.
    +    //
    +
    +    @Override
    +    public String getAlgorithmName()
    +    {
    +        return "SHA-224";
    +    }
    +
    +    @Override
    +    public int getDigestSize()
    +    {
    +        return getDigestSize(nativeRef.getReference());
    +    }
    +
    +
    +    @Override
    +    public void update(byte in)
    +    {
    +        try
    +        {
    +            update(nativeRef.getReference(), in);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void update(byte[] input, int inOff, int len)
    +    {
    +        try
    +        {
    +            update(nativeRef.getReference(), input, inOff, len);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int doFinal(byte[] output, int outOff)
    +    {
    +        try
    +        {
    +            return doFinal(nativeRef.getReference(), output, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void reset()
    +    {
    +        try
    +        {
    +            reset(nativeRef.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int getByteLength()
    +    {
    +        try
    +        {
    +            return getByteLength(nativeRef.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public Memoable copy()
    +    {
    +        try
    +        {
    +            return new SHA224NativeDigest(this);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public void reset(Memoable other)
    +    {
    +        try
    +        {
    +            SHA224NativeDigest dig = (SHA224NativeDigest) other;
    +            restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    public byte[] getEncodedState()
    +    {
    +        try
    +        {
    +            int l = encodeFullState(nativeRef.getReference(), null, 0);
    +            byte[] state = new byte[l];
    +            encodeFullState(nativeRef.getReference(), state, 0);
    +            return state;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    void restoreFullState(byte[] encoded, int offset)
    +    {
    +        try
    +        {
    +            restoreFullState(nativeRef.getReference(), encoded, offset);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public String toString()
    +    {
    +        return "SHA224[Native]()";
    +    }
    +
    +    static native long makeNative();
    +
    +    static native void destroy(long nativeRef);
    +
    +    static native int getDigestSize(long nativeRef);
    +
    +    static native void update(long nativeRef, byte in);
    +
    +    static native void update(long nativeRef, byte[] in, int inOff, int len);
    +
    +    static native int doFinal(long nativeRef, byte[] out, int outOff);
    +
    +    static native void reset(long nativeRef);
    +
    +    static native int getByteLength(long nativeRef);
    +
    +    static native int encodeFullState(long nativeRef, byte[] buffer, int offset);
    +
    +    static native void restoreFullState(long reference, byte[] encoded, int offset);
    +
    +    protected CryptoServiceProperties cryptoServiceProperties()
    +    {
    +        return Utils.getDefaultProperties(this, 224, purpose);
    +    }
    +
    +
    +    private static class Disposer
    +            extends NativeDisposer
    +    {
    +
    +        Disposer(long ref)
    +        {
    +            super(ref);
    +        }
    +
    +        @Override
    +        protected void dispose(long reference)
    +        {
    +            destroy(reference);
    +        }
    +    }
    +
    +    private static class DigestRefWrapper
    +            extends NativeReference
    +    {
    +
    +        public DigestRefWrapper(long reference)
    +        {
    +            super(reference, "SHA224");
    +        }
    +
    +        @Override
    +        public Runnable createAction()
    +        {
    +            return new Disposer(reference);
    +        }
    +    }
    +}
    +
    +
    +
    +
    +
    +
    
  • core/src/main/java9/org/bouncycastle/crypto/digests/SHA256NativeDigest.java+284 0 added
    @@ -0,0 +1,284 @@
    +package org.bouncycastle.crypto.digests;
    +
    +import org.bouncycastle.crypto.CryptoServiceProperties;
    +import org.bouncycastle.crypto.CryptoServicePurpose;
    +import org.bouncycastle.crypto.CryptoServicesRegistrar;
    +import org.bouncycastle.crypto.SavableDigest;
    +import org.bouncycastle.util.Memoable;
    +import org.bouncycastle.util.dispose.NativeDisposer;
    +import org.bouncycastle.util.dispose.NativeReference;
    +
    +import java.lang.ref.Reference;
    +
    +/**
    + * SHA256 implementation.
    + */
    +class SHA256NativeDigest
    +        implements SavableDigest
    +{
    +    private final CryptoServicePurpose purpose;
    +
    +    protected DigestRefWrapper nativeRef = null;
    +
    +    SHA256NativeDigest(CryptoServicePurpose purpose)
    +    {
    +        this.purpose = purpose;
    +        nativeRef = new DigestRefWrapper(makeNative());
    +        reset();
    +        CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
    +    }
    +
    +    SHA256NativeDigest()
    +    {
    +        this(CryptoServicePurpose.ANY);
    +    }
    +
    +    SHA256NativeDigest(SHA256NativeDigest src)
    +    {
    +
    +        this(CryptoServicePurpose.ANY);
    +
    +        byte[] state = src.getEncodedState();
    +
    +        restoreFullState(nativeRef.getReference(), state, 0);
    +    }
    +
    +    //
    +    // From BC-LTS, used for testing in FIPS api only.
    +    // ----------------------- Start Testing only methods.
    +
    +    SHA256NativeDigest restoreState(byte[] state, int offset)
    +    {
    +        restoreFullState(nativeRef.getReference(), state, offset);
    +        return this;
    +    }
    +
    +    //
    +    // ----------------------- End Testing only methods.
    +    //
    +
    +    @Override
    +    public String getAlgorithmName()
    +    {
    +        try
    +        {
    +            return "SHA-256";
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int getDigestSize()
    +    {
    +        try
    +        {
    +            return getDigestSize(nativeRef.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void update(byte in)
    +    {
    +
    +        try
    +        {
    +            update(nativeRef.getReference(), in);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void update(byte[] input, int inOff, int len)
    +    {
    +        try
    +        {
    +            update(nativeRef.getReference(), input, inOff, len);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int doFinal(byte[] output, int outOff)
    +    {
    +        try
    +        {
    +            return doFinal(nativeRef.getReference(), output, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void reset()
    +    {
    +        try
    +        {
    +            reset(nativeRef.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int getByteLength()
    +    {
    +        try
    +        {
    +            return getByteLength(nativeRef.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public Memoable copy()
    +    {
    +        try
    +        {
    +            return new SHA256NativeDigest(this);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public void reset(Memoable other)
    +    {
    +        try
    +        {
    +            SHA256NativeDigest dig = (SHA256NativeDigest) other;
    +            restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    public byte[] getEncodedState()
    +    {
    +        try
    +        {
    +            int l = encodeFullState(nativeRef.getReference(), null, 0);
    +            byte[] state = new byte[l];
    +            encodeFullState(nativeRef.getReference(), state, 0);
    +            return state;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    void restoreFullState(byte[] encoded, int offset)
    +    {
    +        try
    +        {
    +            restoreFullState(nativeRef.getReference(), encoded, offset);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public String toString()
    +    {
    +        return "SHA256[Native]()";
    +    }
    +
    +    static native long makeNative();
    +
    +    static native void destroy(long nativeRef);
    +
    +    static native int getDigestSize(long nativeRef);
    +
    +    static native void update(long nativeRef, byte in);
    +
    +    static native void update(long nativeRef, byte[] in, int inOff, int len);
    +
    +    static native int doFinal(long nativeRef, byte[] out, int outOff);
    +
    +    static native void reset(long nativeRef);
    +
    +    static native int getByteLength(long nativeRef);
    +
    +    static native int encodeFullState(long nativeRef, byte[] buffer, int offset);
    +
    +    static native void restoreFullState(long reference, byte[] encoded, int offset);
    +
    +    protected CryptoServiceProperties cryptoServiceProperties()
    +    {
    +        return Utils.getDefaultProperties(this, 256, purpose);
    +    }
    +
    +
    +    private static class Disposer
    +            extends NativeDisposer
    +    {
    +
    +        Disposer(long ref)
    +        {
    +            super(ref);
    +        }
    +
    +        @Override
    +        protected void dispose(long reference)
    +        {
    +            destroy(reference);
    +        }
    +    }
    +
    +    private static class DigestRefWrapper
    +            extends NativeReference
    +    {
    +
    +        public DigestRefWrapper(long reference)
    +        {
    +            super(reference, "SHA256");
    +        }
    +
    +        @Override
    +        public Runnable createAction()
    +        {
    +            return new Disposer(reference);
    +        }
    +    }
    +}
    +
    +
    +
    +
    +
    +
    
  • core/src/main/java9/org/bouncycastle/crypto/digests/SHA384NativeDigest.java+259 0 added
    @@ -0,0 +1,259 @@
    +package org.bouncycastle.crypto.digests;
    +
    +import org.bouncycastle.crypto.CryptoServiceProperties;
    +import org.bouncycastle.crypto.CryptoServicePurpose;
    +import org.bouncycastle.crypto.CryptoServicesRegistrar;
    +import org.bouncycastle.crypto.SavableDigest;
    +import org.bouncycastle.util.Memoable;
    +import org.bouncycastle.util.dispose.NativeDisposer;
    +import org.bouncycastle.util.dispose.NativeReference;
    +
    +import java.lang.ref.Reference;
    +
    +/**
    + * SHA384 implementation.
    + */
    +class SHA384NativeDigest
    +        implements SavableDigest
    +{
    +    private final CryptoServicePurpose purpose;
    +
    +    protected DigestRefWrapper nativeRef = null;
    +
    +    SHA384NativeDigest(CryptoServicePurpose purpose)
    +    {
    +        this.purpose = purpose;
    +        nativeRef = new DigestRefWrapper(makeNative());
    +        reset();
    +        CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
    +    }
    +
    +    SHA384NativeDigest()
    +    {
    +        this(CryptoServicePurpose.ANY);
    +    }
    +
    +    SHA384NativeDigest(SHA384NativeDigest src)
    +    {
    +
    +        this(CryptoServicePurpose.ANY);
    +
    +        byte[] state = src.getEncodedState();
    +
    +        restoreFullState(nativeRef.getReference(), state, 0);
    +    }
    +
    +    //
    +    // From BC-LTS, used for testing in FIPS api only.
    +    // ----------------------- Start Testing only methods.
    +
    +    SHA384NativeDigest restoreState(byte[] state, int offset)
    +    {
    +        restoreFullState(nativeRef.getReference(), state, offset);
    +        return this;
    +    }
    +
    +    //
    +    // ----------------------- End Testing only methods.
    +    //
    +
    +    @Override
    +    public String getAlgorithmName()
    +    {
    +        try {
    +        return "SHA-384";
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int getDigestSize()
    +    {
    +        try {
    +        return getDigestSize(nativeRef.getReference());
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void update(byte in)
    +    {
    +try {
    +        update(nativeRef.getReference(), in);
    +} finally
    +{
    +    Reference.reachabilityFence(this);
    +}
    +    }
    +
    +
    +    @Override
    +    public void update(byte[] input, int inOff, int len)
    +    {
    +        try {
    +        update(nativeRef.getReference(), input, inOff, len);
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int doFinal(byte[] output, int outOff)
    +    {
    +        try {
    +        return doFinal(nativeRef.getReference(), output, outOff);
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void reset()
    +    {
    +        try {
    +        reset(nativeRef.getReference());
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int getByteLength()
    +    {
    +        try {
    +        return getByteLength(nativeRef.getReference());
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public Memoable copy()
    +    {
    +        return new SHA384NativeDigest(this);
    +    }
    +
    +    @Override
    +    public void reset(Memoable other)
    +    {
    +        try {
    +        SHA384NativeDigest dig = (SHA384NativeDigest) other;
    +        restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    public byte[] getEncodedState()
    +    {
    +        try {
    +        int l = encodeFullState(nativeRef.getReference(), null, 0);
    +        byte[] state = new byte[l];
    +        encodeFullState(nativeRef.getReference(), state, 0);
    +        return state;
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +
    +
    +    void restoreFullState(byte[] encoded, int offset)
    +    {
    +        try {
    +        restoreFullState(nativeRef.getReference(), encoded, offset);
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +
    +    @Override
    +    public String toString()
    +    {
    +        return "SHA384[Native]()";
    +    }
    +
    +    static native long makeNative();
    +
    +    static native void destroy(long nativeRef);
    +
    +    static native int getDigestSize(long nativeRef);
    +
    +    static native void update(long nativeRef, byte in);
    +
    +    static native void update(long nativeRef, byte[] in, int inOff, int len);
    +
    +    static native int doFinal(long nativeRef, byte[] out, int outOff);
    +
    +    static native void reset(long nativeRef);
    +
    +    static native int getByteLength(long nativeRef);
    +
    +    static native int encodeFullState(long nativeRef, byte[] buffer, int offset);
    +
    +    static native void restoreFullState(long reference, byte[] encoded, int offset);
    +
    +    protected CryptoServiceProperties cryptoServiceProperties()
    +    {
    +        return Utils.getDefaultProperties(this, 384, purpose);
    +    }
    +
    +
    +    private static class Disposer
    +            extends NativeDisposer
    +    {
    +
    +        Disposer(long ref)
    +        {
    +            super(ref);
    +        }
    +
    +        @Override
    +        protected void dispose(long reference)
    +        {
    +            destroy(reference);
    +        }
    +    }
    +
    +    private static class DigestRefWrapper
    +            extends NativeReference
    +    {
    +
    +        public DigestRefWrapper(long reference)
    +        {
    +            super(reference,"SHA384");
    +        }
    +
    +        @Override
    +        public Runnable createAction()
    +        {
    +            return new Disposer(reference);
    +        }
    +    }
    +}
    +
    +
    +
    +
    +
    +
    
  • core/src/main/java9/org/bouncycastle/crypto/digests/SHA3NativeDigest.java+316 0 added
    @@ -0,0 +1,316 @@
    +package org.bouncycastle.crypto.digests;
    +
    +import org.bouncycastle.crypto.*;
    +import org.bouncycastle.util.Memoable;
    +import org.bouncycastle.util.dispose.NativeDisposer;
    +import org.bouncycastle.util.dispose.NativeReference;
    +
    +import java.lang.ref.Reference;
    +
    +/**
    + * SHA3 implementation.
    + */
    +public class SHA3NativeDigest
    +        implements SavableDigest
    +{
    +    private final CryptoServicePurpose purpose;
    +
    +    protected DigestRefWrapper nativeRef = null;
    +    private int bitLen;
    +
    +
    +    public SHA3NativeDigest(CryptoServicePurpose purpose)
    +    {
    +        this(256, purpose);
    +    }
    +
    +    public SHA3NativeDigest(int bitLen, CryptoServicePurpose purpose)
    +    {
    +        if (!CryptoServicesRegistrar.hasEnabledService(NativeServices.SHA3))
    +        {
    +            throw new IllegalStateException("no native SHA3 support");
    +        }
    +
    +        this.purpose = purpose;
    +        this.bitLen = bitLen;
    +        nativeRef = new DigestRefWrapper(makeNative(bitLen));
    +        reset();
    +        CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
    +    }
    +
    +    public SHA3NativeDigest(int bitLen)
    +    {
    +        this(bitLen, CryptoServicePurpose.ANY);
    +    }
    +
    +    public SHA3NativeDigest()
    +    {
    +        this(CryptoServicePurpose.ANY);
    +    }
    +
    +    public SHA3NativeDigest(SHA3NativeDigest src)
    +    {
    +
    +        this(CryptoServicePurpose.ANY);
    +
    +        byte[] state = src.getEncodedState();
    +
    +        restoreFullState(nativeRef.getReference(), state, 0);
    +    }
    +
    +    public SHA3NativeDigest(byte[] encoded, CryptoServicePurpose purpose)
    +    {
    +        this(purpose);
    +        restoreFullState(nativeRef.getReference(), encoded, 0);
    +    }
    +
    +    public SHA3NativeDigest(byte[] encoded)
    +    {
    +        this();
    +        restoreFullState(nativeRef.getReference(), encoded, 0);
    +    }
    +
    +
    +    SHA3NativeDigest restoreState(byte[] state, int offset)
    +    {
    +        try
    +        {
    +            restoreFullState(nativeRef.getReference(), state, offset);
    +            return this;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    //
    +    // ----------------------- End Testing only methods.
    +    //
    +
    +    @Override
    +    public String getAlgorithmName()
    +    {
    +        try
    +        {
    +            return "SHA3-" + bitLen;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int getDigestSize()
    +    {
    +        try
    +        {
    +            return getDigestSize(nativeRef.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void update(byte in)
    +    {
    +        try
    +        {
    +            update(nativeRef.getReference(), in);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void update(byte[] input, int inOff, int len)
    +    {
    +        try
    +        {
    +            update(nativeRef.getReference(), input, inOff, len);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int doFinal(byte[] output, int outOff)
    +    {
    +        try
    +        {
    +            int i = doFinal(nativeRef.getReference(), output, outOff);
    +            reset();
    +            return i;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void reset()
    +    {
    +        try
    +        {
    +            reset(nativeRef.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int getByteLength()
    +    {
    +        try
    +        {
    +            return getByteLength(nativeRef.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public Memoable copy()
    +    {
    +        try
    +        {
    +            return new SHA3NativeDigest(this);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public void reset(Memoable other)
    +    {
    +        try
    +        {
    +            SHA3NativeDigest dig = (SHA3NativeDigest) other;
    +            restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    public byte[] getEncodedState()
    +    {
    +        try
    +        {
    +            int l = encodeFullState(nativeRef.getReference(), null, 0);
    +            byte[] state = new byte[l];
    +            encodeFullState(nativeRef.getReference(), state, 0);
    +            return state;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    void restoreFullState(byte[] encoded, int offset)
    +    {
    +        try
    +        {
    +            restoreFullState(nativeRef.getReference(), encoded, offset);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public String toString()
    +    {
    +        return "SHA3[Native]()";
    +    }
    +
    +    static native long makeNative(int bitLen);
    +
    +    static native void destroy(long nativeRef);
    +
    +    static native int getDigestSize(long nativeRef);
    +
    +    static native void update(long nativeRef, byte in);
    +
    +    static native void update(long nativeRef, byte[] in, int inOff, int len);
    +
    +    static native int doFinal(long nativeRef, byte[] out, int outOff);
    +
    +    static native void reset(long nativeRef);
    +
    +    static native int getByteLength(long nativeRef);
    +
    +    static native int encodeFullState(long nativeRef, byte[] buffer, int offset);
    +
    +    static native void restoreFullState(long reference, byte[] encoded, int offset);
    +
    +    protected CryptoServiceProperties cryptoServiceProperties()
    +    {
    +        return Utils.getDefaultProperties(this, bitLen, purpose);
    +    }
    +
    +
    +    private static class Disposer
    +            extends NativeDisposer
    +    {
    +
    +        Disposer(long ref)
    +        {
    +            super(ref);
    +        }
    +
    +        @Override
    +        protected void dispose(long reference)
    +        {
    +            destroy(reference);
    +        }
    +    }
    +
    +    protected static class DigestRefWrapper
    +            extends NativeReference
    +    {
    +
    +        public DigestRefWrapper(long reference)
    +        {
    +            super(reference, "SHA3");
    +        }
    +
    +        @Override
    +        public Runnable createAction()
    +        {
    +            return new Disposer(reference);
    +        }
    +    }
    +}
    +
    +
    +
    +
    +
    +
    
  • core/src/main/java9/org/bouncycastle/crypto/digests/SHA512NativeDigest.java+271 0 added
    @@ -0,0 +1,271 @@
    +package org.bouncycastle.crypto.digests;
    +
    +import org.bouncycastle.crypto.CryptoServiceProperties;
    +import org.bouncycastle.crypto.CryptoServicePurpose;
    +import org.bouncycastle.crypto.CryptoServicesRegistrar;
    +import org.bouncycastle.crypto.SavableDigest;
    +import org.bouncycastle.util.Memoable;
    +import org.bouncycastle.util.dispose.NativeDisposer;
    +import org.bouncycastle.util.dispose.NativeReference;
    +
    +import java.lang.ref.Reference;
    +
    +/**
    + * SHA512 implementation.
    + */
    +class SHA512NativeDigest
    +        implements SavableDigest
    +{
    +    private final CryptoServicePurpose purpose;
    +
    +    protected DigestRefWrapper nativeRef = null;
    +
    +    SHA512NativeDigest(CryptoServicePurpose purpose)
    +    {
    +        this.purpose = purpose;
    +        nativeRef = new DigestRefWrapper(makeNative());
    +        reset();
    +        CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
    +    }
    +
    +    SHA512NativeDigest()
    +    {
    +        this(CryptoServicePurpose.ANY);
    +    }
    +
    +    SHA512NativeDigest(SHA512NativeDigest src)
    +    {
    +
    +        this(CryptoServicePurpose.ANY);
    +
    +        byte[] state = src.getEncodedState();
    +
    +        restoreFullState(nativeRef.getReference(), state, 0);
    +    }
    +
    +    //
    +    // From BC-LTS, used for testing in FIPS api only.
    +    // ----------------------- Start Testing only methods.
    +
    +    SHA512NativeDigest restoreState(byte[] state, int offset)
    +    {
    +        try
    +        {
    +            restoreFullState(nativeRef.getReference(), state, offset);
    +            return this;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    //
    +    // ----------------------- End Testing only methods.
    +    //
    +
    +    @Override
    +    public String getAlgorithmName()
    +    {
    +        try
    +        {
    +            return "SHA-512";
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int getDigestSize()
    +    {
    +        try {
    +        return getDigestSize(nativeRef.getReference());
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void update(byte in)
    +    {
    +
    +        try {
    +        update(nativeRef.getReference(), in);
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void update(byte[] input, int inOff, int len)
    +    {
    +        try {
    +        update(nativeRef.getReference(), input, inOff, len);
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int doFinal(byte[] output, int outOff)
    +    {
    +        try {
    +        return doFinal(nativeRef.getReference(), output, outOff);
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void reset()
    +    {
    +        try {
    +        reset(nativeRef.getReference());
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int getByteLength()
    +    {
    +        try {
    +        return getByteLength(nativeRef.getReference());
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public Memoable copy()
    +    {
    +        try {
    +        return new SHA512NativeDigest(this);
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public void reset(Memoable other)
    +    {
    +        try {
    +        SHA512NativeDigest dig = (SHA512NativeDigest) other;
    +        restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    public byte[] getEncodedState()
    +    {
    +        try {
    +        int l = encodeFullState(nativeRef.getReference(), null, 0);
    +        byte[] state = new byte[l];
    +        encodeFullState(nativeRef.getReference(), state, 0);
    +        return state;
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    void restoreFullState(byte[] encoded, int offset)
    +    {
    +        try {
    +        restoreFullState(nativeRef.getReference(), encoded, offset);
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public String toString()
    +    {
    +        return "SHA512[Native]()";
    +    }
    +
    +    static native long makeNative();
    +
    +    static native void destroy(long nativeRef);
    +
    +    static native int getDigestSize(long nativeRef);
    +
    +    static native void update(long nativeRef, byte in);
    +
    +    static native void update(long nativeRef, byte[] in, int inOff, int len);
    +
    +    static native int doFinal(long nativeRef, byte[] out, int outOff);
    +
    +    static native void reset(long nativeRef);
    +
    +    static native int getByteLength(long nativeRef);
    +
    +    static native int encodeFullState(long nativeRef, byte[] buffer, int offset);
    +
    +    static native void restoreFullState(long reference, byte[] encoded, int offset);
    +
    +    protected CryptoServiceProperties cryptoServiceProperties()
    +    {
    +        return Utils.getDefaultProperties(this, 512, purpose);
    +    }
    +
    +
    +    private static class Disposer
    +            extends NativeDisposer
    +    {
    +
    +        Disposer(long ref)
    +        {
    +            super(ref);
    +        }
    +
    +        @Override
    +        protected void dispose(long reference)
    +        {
    +            destroy(reference);
    +        }
    +    }
    +
    +    private static class DigestRefWrapper
    +            extends NativeReference
    +    {
    +
    +        public DigestRefWrapper(long reference)
    +        {
    +            super(reference, "SHA512");
    +        }
    +
    +        @Override
    +        public Runnable createAction()
    +        {
    +            return new Disposer(reference);
    +        }
    +    }
    +}
    +
    +
    +
    +
    +
    +
    
  • core/src/main/java9/org/bouncycastle/crypto/digests/SHAKENativeDigest.java+337 0 added
    @@ -0,0 +1,337 @@
    +package org.bouncycastle.crypto.digests;
    +
    +import org.bouncycastle.crypto.*;
    +import org.bouncycastle.util.Memoable;
    +import org.bouncycastle.util.dispose.NativeDisposer;
    +import org.bouncycastle.util.dispose.NativeReference;
    +
    +import java.lang.ref.Reference;
    +
    +/**
    + * SHAKE implementation.
    + */
    +public class SHAKENativeDigest
    +        implements SavableDigestXof
    +{
    +    private final CryptoServicePurpose purpose;
    +
    +    protected DigestRefWrapper nativeRef = null;
    +    private int bitLen;
    +
    +
    +    public SHAKENativeDigest(CryptoServicePurpose purpose)
    +    {
    +        this(128, purpose);
    +    }
    +
    +    public SHAKENativeDigest(int bitLen, CryptoServicePurpose purpose)
    +    {
    +        if (!CryptoServicesRegistrar.hasEnabledService(NativeServices.SHA3))
    +        {
    +            throw new IllegalStateException("no native SHAKE support");
    +        }
    +
    +        this.purpose = purpose;
    +        this.bitLen = bitLen;
    +        nativeRef = new DigestRefWrapper(makeNative(bitLen));
    +        reset();
    +        CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties());
    +    }
    +
    +    public SHAKENativeDigest(int bitLen)
    +    {
    +        this(bitLen, CryptoServicePurpose.ANY);
    +    }
    +
    +    public SHAKENativeDigest()
    +    {
    +        this(CryptoServicePurpose.ANY);
    +    }
    +
    +    public SHAKENativeDigest(SHAKENativeDigest src)
    +    {
    +        this(CryptoServicePurpose.ANY);
    +        byte[] state = src.getEncodedState();
    +        restoreFullState(nativeRef.getReference(), state, 0);
    +    }
    +
    +    public SHAKENativeDigest(byte[] encoded, CryptoServicePurpose purpose)
    +    {
    +        this(purpose);
    +        restoreFullState(nativeRef.getReference(), encoded, 0);
    +    }
    +
    +    public SHAKENativeDigest(byte[] encoded)
    +    {
    +        this();
    +        restoreFullState(nativeRef.getReference(), encoded, 0);
    +    }
    +
    +
    +    SHAKENativeDigest restoreState(byte[] state, int offset)
    +    {
    +        try
    +        {
    +            restoreFullState(nativeRef.getReference(), state, offset);
    +            return this;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    //
    +    // ----------------------- End Testing only methods.
    +    //
    +
    +    @Override
    +    public String getAlgorithmName()
    +    {
    +
    +        return "SHAKE" + bitLen;
    +    }
    +
    +    @Override
    +    public int getDigestSize()
    +    {
    +        try
    +        {
    +            return getDigestSize(nativeRef.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void update(byte in)
    +    {
    +        try
    +        {
    +            update(nativeRef.getReference(), in);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void update(byte[] input, int inOff, int len)
    +    {
    +        try
    +        {
    +            update(nativeRef.getReference(), input, inOff, len);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int doFinal(byte[] output, int outOff)
    +    {
    +        try
    +        {
    +            int i = doFinal(nativeRef.getReference(), output, outOff);
    +            return i;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int doFinal(byte[] out, int outOff, int outLen)
    +    {
    +        try
    +        {
    +            int i = doFinal(nativeRef.getReference(), out, outOff, outLen);
    +            return i;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int doOutput(byte[] out, int outOff, int outLen)
    +    {
    +        try
    +        {
    +            return doOutput(nativeRef.getReference(), out, outOff, outLen);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void reset()
    +    {
    +        try
    +        {
    +            reset(nativeRef.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int getByteLength()
    +    {
    +        try
    +        {
    +            return getByteLength(nativeRef.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public Memoable copy()
    +    {
    +        try
    +        {
    +            return new SHAKENativeDigest(this);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public void reset(Memoable other)
    +    {
    +        try
    +        {
    +            SHAKENativeDigest dig = (SHAKENativeDigest) other;
    +            restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    public byte[] getEncodedState()
    +    {
    +        try
    +        {
    +            int l = encodeFullState(nativeRef.getReference(), null, 0);
    +            byte[] state = new byte[l];
    +            encodeFullState(nativeRef.getReference(), state, 0);
    +            return state;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    void restoreFullState(byte[] encoded, int offset)
    +    {
    +        try
    +        {
    +            restoreFullState(nativeRef.getReference(), encoded, offset);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public String toString()
    +    {
    +        return "SHAKE[Native]()";
    +    }
    +
    +    static native long makeNative(int bitLen);
    +
    +    static native void destroy(long nativeRef);
    +
    +    static native int getDigestSize(long nativeRef);
    +
    +    static native void update(long nativeRef, byte in);
    +
    +    static native void update(long nativeRef, byte[] in, int inOff, int len);
    +
    +    static native int doFinal(long nativeRef, byte[] out, int outOff, int len);
    +
    +    static native int doFinal(long nativeRef, byte[] out, int outOff);
    +
    +    static native int doOutput(long nativeRef, byte[] out, int outOff, int len);
    +
    +    static native void reset(long nativeRef);
    +
    +    static native int getByteLength(long nativeRef);
    +
    +    static native int encodeFullState(long nativeRef, byte[] buffer, int offset);
    +
    +    static native void restoreFullState(long reference, byte[] encoded, int offset);
    +
    +    protected CryptoServiceProperties cryptoServiceProperties()
    +    {
    +        return Utils.getDefaultProperties(this, bitLen, purpose);
    +    }
    +
    +
    +    private static class Disposer
    +            extends NativeDisposer
    +    {
    +
    +        Disposer(long ref)
    +        {
    +            super(ref);
    +        }
    +
    +        @Override
    +        protected void dispose(long reference)
    +        {
    +            destroy(reference);
    +        }
    +    }
    +
    +    protected static class DigestRefWrapper
    +            extends NativeReference
    +    {
    +
    +        public DigestRefWrapper(long reference)
    +        {
    +            super(reference, "SHAKE");
    +        }
    +
    +        @Override
    +        public Runnable createAction()
    +        {
    +            return new Disposer(reference);
    +        }
    +    }
    +}
    +
    +
    +
    +
    +
    +
    
  • core/src/main/java9/org/bouncycastle/crypto/engines/AESNativeCBC.java+306 0 added
    @@ -0,0 +1,306 @@
    +package org.bouncycastle.crypto.engines;
    +
    +import org.bouncycastle.crypto.BlockCipher;
    +import org.bouncycastle.crypto.CipherParameters;
    +import org.bouncycastle.crypto.DataLengthException;
    +import org.bouncycastle.crypto.MultiBlockCipher;
    +import org.bouncycastle.crypto.modes.CBCModeCipher;
    +import org.bouncycastle.crypto.params.KeyParameter;
    +import org.bouncycastle.crypto.params.ParametersWithIV;
    +import org.bouncycastle.util.Arrays;
    +import org.bouncycastle.util.dispose.NativeDisposer;
    +import org.bouncycastle.util.dispose.NativeReference;
    +
    +import java.lang.ref.Reference;
    +
    +class AESNativeCBC
    +        implements CBCModeCipher
    +{
    +    private CBCRefWrapper referenceWrapper;
    +
    +    byte[] IV = new byte[16];
    +    int keySize;
    +
    +    private boolean encrypting;
    +
    +    @Override
    +    public void init(boolean forEncryption, CipherParameters params)
    +            throws IllegalArgumentException
    +    {
    +        try
    +        {
    +            boolean oldEncrypting = this.encrypting;
    +
    +            this.encrypting = forEncryption;
    +
    +            if (params instanceof ParametersWithIV)
    +            {
    +                ParametersWithIV ivParam = (ParametersWithIV) params;
    +                byte[] iv = ivParam.getIV();
    +
    +                if (iv.length != getBlockSize())
    +                {
    +                    throw new IllegalArgumentException("initialisation vector must be the same length as block size");
    +                }
    +
    +                System.arraycopy(iv, 0, IV, 0, iv.length);
    +
    +                reset();
    +
    +                // if null it's an IV changed only.
    +                if (ivParam.getParameters() != null)
    +                {
    +                    init((KeyParameter) ivParam.getParameters());
    +                    // cipher.init(encrypting, ivParam.getParameters());
    +                }
    +                else
    +                {
    +                    // The key parameter was null which inidicates that they
    +                    // IV is being changed.
    +
    +                    if (oldEncrypting != encrypting)
    +                    {
    +                        throw new IllegalArgumentException("cannot change encrypting state without providing key");
    +                    }
    +
    +                    if (referenceWrapper == null)
    +                    {
    +                        throw new IllegalStateException("IV change attempted but not previously initialized with a key");
    +                    }
    +
    +                    // We need to use the old key because
    +                    // the native layer requires a both key and iv each time.
    +                    init(new KeyParameter(referenceWrapper.oldKey));
    +
    +                }
    +            }
    +            else
    +            {
    +                reset();
    +
    +                // if it's null, key is to be reused.
    +                if (params != null)
    +                {
    +                    init((KeyParameter) params);
    +                    // cipher.init(encrypting, params);
    +                }
    +                else
    +                {
    +                    if (oldEncrypting != encrypting)
    +                    {
    +                        throw new IllegalArgumentException("cannot change encrypting state without providing key.");
    +                    }
    +
    +                    if (referenceWrapper == null)
    +                    {
    +                        throw new IllegalStateException("IV change attempted but not previously initialized with a key");
    +                    }
    +
    +                    // We need to use the old key because the
    +                    // native layer requires a both key and iv each time.
    +                    init(new KeyParameter(referenceWrapper.oldKey));
    +
    +                }
    +            }
    +
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    private void init(KeyParameter parameters)
    +    {
    +
    +        try
    +        {
    +            byte[] key = ((KeyParameter) parameters).getKey();
    +
    +
    +            switch (key.length)
    +            {
    +                case 16:
    +                case 24:
    +                case 32:
    +                    break;
    +                default:
    +                    throw new IllegalArgumentException("key must be only 16,24,or 32 bytes long.");
    +            }
    +
    +            referenceWrapper = new CBCRefWrapper(makeNative(key.length, encrypting), Arrays.clone(key));
    +
    +            if (referenceWrapper.getReference() == 0)
    +            {
    +                throw new IllegalStateException("Native CBC native instance returned a null pointer.");
    +            }
    +
    +            init(referenceWrapper.getReference(), key, IV);
    +            keySize = key.length * 8;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public String getAlgorithmName()
    +    {
    +        return "AES/CBC";
    +    }
    +
    +    @Override
    +    public int getBlockSize()
    +    {
    +        return getBlockSize(0);
    +    }
    +
    +
    +    @Override
    +    public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
    +            throws DataLengthException, IllegalStateException
    +    {
    +
    +        try
    +        {
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +
    +            return process(referenceWrapper.getReference(), in, inOff, 1, out, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public void reset()
    +    {
    +        try
    +        {
    +            // skip over spurious resets that may occur before init is called.
    +            if (referenceWrapper == null)
    +            {
    +                return;
    +            }
    +
    +            reset(referenceWrapper.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int getMultiBlockSize()
    +    {
    +        try
    +        {
    +            return getMultiBlockSize(0);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int processBlocks(byte[] in, int inOff, int blockCount, byte[] out, int outOff)
    +            throws DataLengthException, IllegalStateException
    +    {
    +        try
    +        {
    +
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +
    +            return process(referenceWrapper.getReference(), in, inOff, blockCount, out, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    private static native int process(long ref, byte[] in, int inOff, int blockCount, byte[] out, int outOff);
    +
    +    private static native int getMultiBlockSize(long ref);
    +
    +    private static native int getBlockSize(long ref);
    +
    +    static native long makeNative(int keyLen, boolean encryption);
    +
    +    native void init(long nativeRef, byte[] key, byte[] iv);
    +
    +    static native void dispose(long ref);
    +
    +    private static native void reset(long nativeRef);
    +
    +    @Override
    +    public BlockCipher getUnderlyingCipher()
    +    {
    +        try
    +        {
    +            MultiBlockCipher eng = AESEngine.newInstance();
    +            eng.init(encrypting, new KeyParameter(referenceWrapper.oldKey));
    +            return eng;
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    private static class Disposer
    +            extends NativeDisposer
    +    {
    +        private final byte[] oldKey;
    +
    +        Disposer(long ref, byte[] oldKey)
    +        {
    +            super(ref);
    +            this.oldKey = oldKey;
    +        }
    +
    +        @Override
    +        protected void dispose(long reference)
    +        {
    +            Arrays.clear(this.oldKey);
    +            AESNativeCBC.dispose(reference);
    +        }
    +    }
    +
    +    private class CBCRefWrapper
    +            extends NativeReference
    +    {
    +        private final byte[] oldKey;
    +
    +        public CBCRefWrapper(long reference, byte[] oldKey)
    +        {
    +            super(reference, "CBC");
    +            this.oldKey = oldKey;
    +        }
    +
    +        @Override
    +        public Runnable createAction()
    +        {
    +            return new Disposer(reference, this.oldKey);
    +        }
    +    }
    +
    +    @Override
    +    public String toString()
    +    {
    +        return "CBC[Native](AES[Native](" + keySize + ")";
    +    }
    +
    +}
    
  • core/src/main/java9/org/bouncycastle/crypto/engines/AESNativeCCM.java+473 0 added
    @@ -0,0 +1,473 @@
    +package org.bouncycastle.crypto.engines;
    +
    +import org.bouncycastle.crypto.*;
    +import org.bouncycastle.crypto.modes.CCMModeCipher;
    +import org.bouncycastle.crypto.params.AEADParameters;
    +import org.bouncycastle.crypto.params.KeyParameter;
    +import org.bouncycastle.crypto.params.ParametersWithIV;
    +import org.bouncycastle.util.Arrays;
    +import org.bouncycastle.util.dispose.NativeDisposer;
    +import org.bouncycastle.util.dispose.NativeReference;
    +
    +import java.io.ByteArrayOutputStream;
    +import java.lang.ref.Reference;
    +
    +class AESNativeCCM
    +        implements CCMModeCipher
    +{
    +    private CCMRefWrapper refWrapper;
    +    private boolean forEncryption = false;
    +    private boolean initialised = false;
    +    private final ExposedByteArrayOutputStream associatedText = new ExposedByteArrayOutputStream();
    +    private final ExposedByteArrayOutputStream data = new ExposedByteArrayOutputStream();
    +
    +    @Override
    +    public BlockCipher getUnderlyingCipher()
    +    {
    +        try
    +        {
    +            BlockCipher engine = AESEngine.newInstance();
    +
    +            if (refWrapper != null && refWrapper.key != null)
    +            {
    +                engine.init(true, new KeyParameter(refWrapper.key));
    +            }
    +
    +            return engine;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    public void init(boolean forEncryption, CipherParameters params)
    +            throws IllegalArgumentException
    +    {
    +        try
    +        {
    +            this.forEncryption = forEncryption;
    +            CipherParameters cipherParameters;
    +            KeyParameter keyParam = null;
    +
    +            byte[] nonce;
    +            byte[] initialAssociatedText;
    +            int macSize;
    +            if (params instanceof AEADParameters)
    +            {
    +                AEADParameters param = (AEADParameters) params;
    +
    +                nonce = param.getNonce();
    +                initialAssociatedText = param.getAssociatedText();
    +                macSize = getMacSize(forEncryption, param.getMacSize());
    +                cipherParameters = param.getKey();
    +            }
    +            else if (params instanceof ParametersWithIV)
    +            {
    +                ParametersWithIV param = (ParametersWithIV) params;
    +
    +                nonce = param.getIV();
    +                initialAssociatedText = null;
    +                macSize = getMacSize(forEncryption, 64);
    +                cipherParameters = param.getParameters();
    +            }
    +            else
    +            {
    +                throw new IllegalArgumentException("invalid parameters passed to CCM");
    +            }
    +
    +            // NOTE: Very basic support for key re-use, but no performance gain from it
    +            if (cipherParameters != null)
    +            {
    +                keyParam = (KeyParameter) cipherParameters;
    +            }
    +
    +            if (keyParam != null)
    +            {
    +                byte[] key = keyParam.getKey();
    +                if (key == null)
    +                {
    +                    throw new IllegalArgumentException("key was null");
    +                }
    +                initRef(key);
    +            }
    +
    +            assert refWrapper != null;
    +
    +            int iatLen = initialAssociatedText != null ? initialAssociatedText.length : 0;
    +            initNative(
    +                    refWrapper.getReference(),
    +                    forEncryption, refWrapper.getKey(),
    +                    nonce, initialAssociatedText, iatLen, macSize * 8);
    +            reset();
    +            initialised = true;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    private void initRef(byte[] key)
    +    {
    +        refWrapper = new CCMRefWrapper(makeInstance(), Arrays.clone(key));
    +    }
    +
    +
    +    @Override
    +    public String getAlgorithmName()
    +    {
    +        return "AES/CCM";
    +    }
    +
    +    @Override
    +    public void processAADByte(byte in)
    +    {
    +
    +        associatedText.write(in);
    +    }
    +
    +
    +    @Override
    +    public void processAADBytes(byte[] in, int inOff, int len)
    +    {
    +
    +        if (inOff < 0)
    +        {
    +            throw new IllegalArgumentException("offset is negative");
    +        }
    +        if (len < 0)
    +        {
    +            throw new IllegalArgumentException("len is negative");
    +        }
    +        if (in.length < inOff + len)
    +        {
    +            throw new IllegalArgumentException("array too short for offset + len");
    +        }
    +        associatedText.write(in, inOff, len);
    +
    +    }
    +
    +
    +    @Override
    +    public int processByte(byte in, byte[] out, int outOff)
    +            throws DataLengthException
    +    {
    +        if (outOff < 0)
    +        {
    +            throw new IllegalArgumentException("offset is negative");
    +        }
    +
    +        if (out != null && out.length < outOff)
    +        {
    +            throw new DataLengthException("offset past end");
    +        }
    +        data.write(in);
    +        return 0;
    +    }
    +
    +
    +    @Override
    +    public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
    +            throws DataLengthException
    +    {
    +        if (inOff < 0 || outOff < 0)
    +        {
    +            throw new IllegalArgumentException("offset is negative");
    +        }
    +        if (len < 0)
    +        {
    +            throw new IllegalArgumentException("len is negative");
    +        }
    +        if (in == null)
    +        {
    +            throw new NullPointerException("input was null");
    +        }
    +        if (in.length < (inOff + len))
    +        {
    +            throw new DataLengthException("array too short for offset + len");
    +        }
    +
    +        data.write(in, inOff, len);
    +
    +
    +        return 0;
    +    }
    +
    +
    +    @Override
    +    public int doFinal(byte[] out, int outOff)
    +            throws IllegalStateException, InvalidCipherTextException
    +    {
    +        try
    +        {
    +            int len;
    +            try
    +            {
    +                checkStatus();
    +                if (out == null)
    +                {
    +                    throw new NullPointerException("output was null");
    +                }
    +                if (outOff < 0)
    +                {
    +                    throw new IllegalArgumentException("offset is negative");
    +                }
    +
    +                if (getOutputSize(0) > out.length - outOff)
    +                {
    +                    throw new OutputLengthException("output buffer too short");
    +                }
    +                len = processPacket(refWrapper.getReference(), data.getBuffer(), 0, data.size(), associatedText.getBuffer(), 0, associatedText.size(), out, outOff);
    +                resetKeepMac();
    +                //
    +                // BlockCipherTest, testing ShortTagException.
    +                //
    +            }
    +            catch (IllegalStateException e)
    +            {
    +                reset();
    +                throw e;
    +            }
    +
    +            return len;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public byte[] getMac()
    +    {
    +        try
    +        {
    +            return getMac(refWrapper.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int getUpdateOutputSize(int len)
    +    {
    +        return 0; // Not relevant in CCM.
    +    }
    +
    +
    +    @Override
    +    public int getOutputSize(int len)
    +    {
    +        try
    +        {
    +            return getOutputSize(refWrapper.getReference(), len + data.size());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void reset()
    +    {
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                // deal with reset being called before init.
    +                return;
    +            }
    +            associatedText.reset();
    +            data.reset();
    +            reset(refWrapper.getReference(), false);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int processPacket(byte[] inBuf, int inOff, int length, byte[] outBuf, int outOff)
    +            throws InvalidCipherTextException
    +    {
    +        try
    +        {
    +            int result = processPacket(refWrapper.getReference(), inBuf, inOff, length, associatedText.getBuffer(), 0, associatedText.size(), outBuf, outOff);
    +            reset();
    +            return result;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public byte[] processPacket(byte[] input, int inOff, int length)
    +            throws InvalidCipherTextException
    +    {
    +        try
    +        {
    +            byte[] out = new byte[getOutputSize(length)];
    +            processPacket(input, inOff, length, out, 0);
    +            reset();
    +            return out;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    private void resetKeepMac()
    +    {
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                // deal with reset being called before init.
    +                return;
    +            }
    +            associatedText.reset();
    +            data.reset();
    +            reset(refWrapper.getReference(), true);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    private void checkStatus()
    +    {
    +        if (!initialised)
    +        {
    +            if (forEncryption)
    +            {
    +                throw new IllegalStateException("CCM cipher cannot be reused for encryption");
    +            }
    +            throw new IllegalStateException("CCM cipher needs to be initialised");
    +        }
    +    }
    +
    +
    +    private native void reset(long ref, boolean keepMac);
    +
    +    static native void initNative(
    +            long reference,
    +            boolean forEncryption,
    +            byte[] keyParam,
    +            byte[] nonce,
    +            byte[] initialAssociatedText,
    +            int initialAssociatedTextLen,
    +            int macSizeBits);
    +
    +    static native long makeInstance();
    +
    +    static native void dispose(long nativeRef);
    +
    +
    +    static native int getOutputSize(long ref, int len);
    +
    +    static native byte[] getMac(long ref);
    +
    +    static native int processPacket(long ref, byte[] in, int inOff, int inLen, byte[] aad, int aadOff, int aadlen,
    +                                    byte[] out, int outOff);
    +
    +
    +    private static class CCMRefWrapper
    +            extends NativeReference
    +    {
    +
    +        private final byte[] key;
    +
    +        public CCMRefWrapper(long reference, byte[] key)
    +        {
    +            super(reference, "CCM");
    +            this.key = key;
    +        }
    +
    +        @Override
    +        public Runnable createAction()
    +        {
    +            return new Disposer(reference, key);
    +        }
    +
    +
    +        public byte[] getKey()
    +        {
    +            return key;
    +        }
    +    }
    +
    +
    +    private static class Disposer
    +            extends NativeDisposer
    +    {
    +
    +        private final byte[] key;
    +
    +
    +        public Disposer(long reference, byte[] key)
    +        {
    +            super(reference);
    +            this.key = key;
    +
    +        }
    +
    +
    +        @Override
    +        protected void dispose(long reference)
    +        {
    +            Arrays.clear(key);
    +            AESNativeCCM.dispose(reference);
    +        }
    +    }
    +
    +    @Override
    +    public String toString()
    +    {
    +        if (refWrapper != null && refWrapper.key != null)
    +        {
    +            return "CCM[Native](AES[Native](" + (refWrapper.key.length * 8) + "))";
    +        }
    +        return "CCM[Native](AES[Native](not initialized))";
    +    }
    +
    +
    +    private int getMacSize(boolean forEncryption, int requestedMacBits)
    +    {
    +        if (forEncryption && (requestedMacBits < 32 || requestedMacBits > 128 || 0 != (requestedMacBits & 15)))
    +        {
    +            throw new IllegalArgumentException("invalid value for MAC size");
    +        }
    +
    +        return requestedMacBits >>> 3;
    +    }
    +
    +    private static class ExposedByteArrayOutputStream
    +            extends ByteArrayOutputStream
    +    {
    +        public ExposedByteArrayOutputStream()
    +        {
    +            super();
    +        }
    +
    +        public byte[] getBuffer()
    +        {
    +            return this.buf;
    +        }
    +    }
    +}
    
  • core/src/main/java9/org/bouncycastle/crypto/engines/AESNativeCFB.java+311 0 added
    @@ -0,0 +1,311 @@
    +package org.bouncycastle.crypto.engines;
    +
    +import org.bouncycastle.crypto.CipherParameters;
    +import org.bouncycastle.crypto.DataLengthException;
    +import org.bouncycastle.crypto.modes.CFBModeCipher;
    +import org.bouncycastle.crypto.params.KeyParameter;
    +import org.bouncycastle.crypto.params.ParametersWithIV;
    +import org.bouncycastle.util.Arrays;
    +import org.bouncycastle.util.dispose.NativeDisposer;
    +import org.bouncycastle.util.dispose.NativeReference;
    +
    +import java.lang.ref.Reference;
    +
    +class AESNativeCFB
    +        implements CFBModeCipher
    +{
    +    private final int bitSize;
    +    private CFBRefWrapper referenceWrapper;
    +
    +    private byte[] oldIv;
    +    private boolean encrypting;
    +
    +    public AESNativeCFB()
    +    {
    +        this(128);
    +    }
    +
    +    public AESNativeCFB(int bitSize)
    +    {
    +        this.bitSize = bitSize;
    +        switch (bitSize)
    +        {
    +            case 128:
    +                break;
    +            default:
    +                throw new IllegalArgumentException("native feedback bit size can only be 128");
    +        }
    +    }
    +
    +    @Override
    +    public void init(boolean forEncryption, CipherParameters params)
    +            throws IllegalArgumentException
    +    {
    +        try
    +        {
    +            boolean oldEncrypting = this.encrypting;
    +
    +            this.encrypting = forEncryption;
    +
    +            byte[] key = null;
    +            byte[] iv = null;
    +
    +            if (params instanceof ParametersWithIV)
    +            {
    +                ParametersWithIV ivParam = (ParametersWithIV) params;
    +                iv = ivParam.getIV();
    +
    +                if (iv.length > getBlockSize() || iv.length < 1)
    +                {
    +                    throw new IllegalArgumentException("initialisation vector must be between one and block size length");
    +                }
    +
    +                if (iv.length < getBlockSize())
    +                {
    +                    byte[] newIv = new byte[getBlockSize()];
    +                    System.arraycopy(iv, 0, newIv, newIv.length - iv.length, iv.length);
    +                    iv = newIv;
    +                }
    +
    +                oldIv = Arrays.clone(iv);
    +
    +                if (ivParam.getParameters() != null)
    +                {
    +                    key = Arrays.clone(((KeyParameter) ivParam.getParameters()).getKey());
    +                }
    +
    +                if (key != null)
    +                {
    +                    oldEncrypting = encrypting; // Can change because key is supplied.
    +                    key = Arrays.clone(key);
    +                }
    +                else
    +                {
    +                    // Use old key, it may be null but that is tested later.
    +                    key = referenceWrapper != null ? referenceWrapper.getKey() : null;
    +                }
    +            }
    +            else
    +            {
    +                //
    +                // Change of key.
    +                //
    +
    +                if (params instanceof KeyParameter)
    +                {
    +                    key = Arrays.clone(((KeyParameter) params).getKey());
    +                    iv = oldIv;
    +                }
    +
    +            }
    +
    +            if (key == null && oldEncrypting != encrypting)
    +            {
    +                throw new IllegalArgumentException("cannot change encrypting state without providing key.");
    +            }
    +
    +            if (iv == null)
    +            {
    +                throw new IllegalArgumentException("iv is null");
    +            }
    +
    +
    +            referenceWrapper = new CFBRefWrapper(makeNative(encrypting, key.length), key);
    +            init(referenceWrapper.getReference(), key, iv);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public String getAlgorithmName()
    +    {
    +        return "AES/CFB";
    +    }
    +
    +    @Override
    +    public byte returnByte(byte in)
    +    {
    +        try
    +        {
    +            return processByte(referenceWrapper.getReference(), in);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
    +            throws DataLengthException
    +    {
    +        try
    +        {
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +
    +
    +            return processBytes(referenceWrapper.getReference(), in, inOff, len, out, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int getBlockSize()
    +    {
    +        return bitSize / 8;
    +    }
    +
    +
    +    @Override
    +    public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
    +            throws DataLengthException, IllegalStateException
    +    {
    +
    +        try
    +        {
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +
    +            return processBytes(referenceWrapper.getReference(), in, inOff, getBlockSize(), out, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public void reset()
    +    {
    +        try
    +        {
    +            // skip over spurious resets that may occur before init is called.
    +            if (referenceWrapper == null)
    +            {
    +                return;
    +            }
    +
    +            reset(referenceWrapper.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int getMultiBlockSize()
    +    {
    +        return getNativeMultiBlockSize();
    +    }
    +
    +    @Override
    +    public int processBlocks(byte[] in, int inOff, int blockCount, byte[] out, int outOff)
    +            throws DataLengthException, IllegalStateException
    +    {
    +        try
    +        {
    +
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("CFB engine not initialized");
    +            }
    +
    +            return processBytes(in, inOff, blockCount * getBlockSize(), out, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    private static native byte processByte(long ref, byte in);
    +
    +    private static native int processBytes(long ref, byte[] in, int inOff, int len, byte[] out, int outOff)
    +            throws DataLengthException;
    +
    +    static native long makeNative(boolean encrypting, int keyLen);
    +
    +    native void init(long nativeRef, byte[] key, byte[] iv);
    +
    +    static native void dispose(long ref);
    +
    +    static native int getNativeMultiBlockSize();
    +
    +    private static native void reset(long nativeRef);
    +
    +
    +    private static class Disposer
    +            extends NativeDisposer
    +    {
    +        private final byte[] key;
    +
    +        Disposer(long ref, byte[] key)
    +        {
    +            super(ref);
    +            this.key = key;
    +        }
    +
    +        @Override
    +        protected void dispose(long reference)
    +        {
    +            Arrays.clear(key);
    +            AESNativeCFB.dispose(reference);
    +        }
    +    }
    +
    +    private static class CFBRefWrapper
    +            extends NativeReference
    +    {
    +
    +        private final byte[] key;
    +
    +        public CFBRefWrapper(long reference, byte[] key)
    +        {
    +            super(reference, "CFB");
    +            this.key = key;
    +        }
    +
    +        public byte[] getKey()
    +        {
    +            return key;
    +        }
    +
    +        @Override
    +        public Runnable createAction()
    +        {
    +            return new Disposer(reference, key);
    +        }
    +    }
    +
    +    public String toString()
    +    {
    +        try
    +        {
    +            if (referenceWrapper != null && referenceWrapper.getKey() != null)
    +            {
    +                return "CFB[Native](AES[Native](" + (referenceWrapper.getKey().length * 8) + "))";
    +            }
    +            return "CFB[Native](AES[Native](not initialized))";
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +}
    
  • core/src/main/java9/org/bouncycastle/crypto/engines/AESNativeCTR.java+357 0 added
    @@ -0,0 +1,357 @@
    +package org.bouncycastle.crypto.engines;
    +
    +import org.bouncycastle.crypto.BlockCipher;
    +import org.bouncycastle.crypto.CipherParameters;
    +import org.bouncycastle.crypto.DataLengthException;
    +import org.bouncycastle.crypto.modes.CTRModeCipher;
    +import org.bouncycastle.crypto.params.KeyParameter;
    +import org.bouncycastle.crypto.params.ParametersWithIV;
    +import org.bouncycastle.util.Arrays;
    +import org.bouncycastle.util.dispose.NativeDisposer;
    +import org.bouncycastle.util.dispose.NativeReference;
    +
    +import java.lang.ref.Reference;
    +
    +public class AESNativeCTR
    +        implements CTRModeCipher
    +{
    +
    +    private CTRRefWrapper referenceWrapper = null;
    +    private int keyLen;
    +
    +
    +    public AESNativeCTR()
    +    {
    +    }
    +
    +
    +    public BlockCipher getUnderlyingCipher()
    +    {
    +        try
    +        {
    +            BlockCipher engine = AESEngine.newInstance();
    +            if (referenceWrapper != null)
    +            {
    +                byte[] k = referenceWrapper.getKey();
    +                if (k != null)
    +                {
    +                    engine.init(true, new KeyParameter(referenceWrapper.getKey()));
    +                }
    +            }
    +            return engine;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int getBlockSize()
    +    {
    +        return 16;
    +    }
    +
    +
    +    @Override
    +    public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
    +            throws DataLengthException, IllegalStateException
    +    {
    +
    +        try
    +        {
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +
    +            return processBytes(referenceWrapper.getReference(), in, inOff, getBlockSize(), out, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int getMultiBlockSize()
    +    {
    +        return getMultiBlockSize(0);
    +    }
    +
    +    @Override
    +    public int processBlocks(byte[] in, int inOff, int blockCount, byte[] out, int outOff)
    +            throws DataLengthException, IllegalStateException
    +    {
    +        try
    +        {
    +            int extent = getBlockSize() * blockCount;
    +
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +
    +            return processBytes(referenceWrapper.getReference(), in, inOff, extent, out, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public long skip(long numberOfBytes)
    +    {
    +        try
    +        {
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +            return skip(referenceWrapper.getReference(), numberOfBytes);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public long seekTo(long position)
    +    {
    +        try
    +        {
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +            return seekTo(referenceWrapper.getReference(), position);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public long getPosition()
    +    {
    +        try
    +        {
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +            return getPosition(referenceWrapper.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void init(boolean forEncryption, CipherParameters params)
    +            throws IllegalArgumentException
    +    {
    +        try
    +        {
    +            if (params instanceof ParametersWithIV)
    +            {
    +                ParametersWithIV ivParam = (ParametersWithIV) params;
    +                byte[] iv = ivParam.getIV();
    +
    +                int blockSize = getBlockSize();
    +
    +                int maxCounterSize = (8 > blockSize / 2) ? blockSize / 2 : 8;
    +
    +                if (blockSize - iv.length > maxCounterSize)
    +                {
    +                    throw new IllegalArgumentException("CTR mode requires IV of at least: " + (blockSize - maxCounterSize) + " bytes.");
    +                }
    +
    +                //
    +                // if null it's an IV changed only.
    +                if (ivParam.getParameters() == null)
    +                {
    +                    if (referenceWrapper == null)
    +                    {
    +                        referenceWrapper = new CTRRefWrapper(makeCTRInstance(), null);
    +                    }
    +                    init(referenceWrapper.getReference(), referenceWrapper.getKey(), iv);
    +                }
    +                else
    +                {
    +                    byte[] key = ((KeyParameter) ivParam.getParameters()).getKey();
    +
    +                    switch (key.length)
    +                    {
    +                        case 16:
    +                        case 24:
    +                        case 32:
    +                            break;
    +                        default:
    +                            throw new IllegalArgumentException("invalid key length, key must be 16,24 or 32 bytes");
    +                    }
    +
    +
    +                    keyLen = key.length * 8;
    +
    +                    referenceWrapper = new CTRRefWrapper(makeCTRInstance(), key);
    +                    init(referenceWrapper.getReference(), referenceWrapper.getKey(), iv);
    +
    +                }
    +
    +                reset();
    +            }
    +            else
    +            {
    +                throw new IllegalArgumentException("CTR mode requires ParametersWithIV");
    +            }
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    static native long makeCTRInstance();
    +
    +    @Override
    +    public String getAlgorithmName()
    +    {
    +        return "AES/CTR";
    +    }
    +
    +    @Override
    +    public byte returnByte(byte in)
    +    {
    +        try
    +        {
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +            return returnByte(referenceWrapper.getReference(), in);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
    +            throws DataLengthException
    +    {
    +        try
    +        {
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +
    +            return processBytes(referenceWrapper.getReference(), in, inOff, len, out, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void reset()
    +    {
    +        try
    +        {
    +            if (referenceWrapper == null)
    +            {
    +                return;
    +            }
    +
    +            reset(referenceWrapper.getReference());
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    private static native long getPosition(long reference);
    +
    +    private static native int getMultiBlockSize(long ref);
    +
    +    private static native long skip(long ref, long numberOfByte);
    +
    +    private static native long seekTo(long ref, long position);
    +
    +    static native void init(long ref, byte[] key, byte[] iv);
    +
    +    private static native byte returnByte(long ref, byte b);
    +
    +    private static native int processBytes(long ref, byte[] in, int inOff, int len, byte[] out, int outOff);
    +
    +    private static native void reset(long ref);
    +
    +
    +    native static void dispose(long ref);
    +
    +
    +    private static class CTRRefWrapper
    +            extends NativeReference
    +    {
    +        private final byte[] key;
    +
    +        public CTRRefWrapper(long reference, byte[] key)
    +        {
    +            super(reference, "CTR");
    +            this.key = key;
    +        }
    +
    +        public byte[] getKey()
    +        {
    +            return key;
    +        }
    +
    +        @Override
    +        public Runnable createAction()
    +        {
    +            return new Disposer(reference, key);
    +        }
    +
    +
    +    }
    +
    +
    +    private static class Disposer
    +            extends NativeDisposer
    +    {
    +        private final byte[] key;
    +
    +        Disposer(long ref, byte[] key)
    +        {
    +            super(ref);
    +            this.key = key;
    +        }
    +
    +        @Override
    +        protected void dispose(long reference)
    +        {
    +            Arrays.clear(key);
    +            AESNativeCTR.dispose(reference);
    +        }
    +    }
    +
    +    public String toString()
    +    {
    +        if (keyLen > 0)
    +        {
    +            return "CTR[Native](AES[Native](" + keyLen + "))";
    +        }
    +        return "CTR[Native](AES[Native](not initialized))";
    +    }
    +
    +}
    
  • core/src/main/java9/org/bouncycastle/crypto/engines/AESNativeEngine.java+281 0 added
    @@ -0,0 +1,281 @@
    +package org.bouncycastle.crypto.engines;
    +
    +import org.bouncycastle.crypto.*;
    +import org.bouncycastle.crypto.constraints.DefaultServiceProperties;
    +import org.bouncycastle.crypto.modes.*;
    +import org.bouncycastle.crypto.params.KeyParameter;
    +import org.bouncycastle.util.dispose.NativeDisposer;
    +import org.bouncycastle.util.dispose.NativeReference;
    +
    +import java.lang.ref.Reference;
    +
    +class AESNativeEngine
    +        extends DefaultMultiBlockCipher
    +        implements NativeBlockCipherProvider, NativeCCMProvider, NativeEAXProvider, NativeOCBProvider, NativeGCMSIVProvider
    +{
    +    protected NativeReference wrapper = null;
    +    private int keyLen = 0;
    +
    +    AESNativeEngine()
    +    {
    +        CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties(getAlgorithmName(), 256));
    +    }
    +
    +    @Override
    +    public void init(boolean forEncryption, CipherParameters params)
    +            throws IllegalArgumentException
    +    {
    +        try
    +        {
    +            if (params instanceof KeyParameter)
    +            {
    +                byte[] key = ((KeyParameter) params).getKey();
    +
    +                switch (key.length)
    +                {
    +                    case 16:
    +                    case 24:
    +                    case 32:
    +                        wrapper = new ECBNativeRef(makeInstance(key.length, forEncryption));
    +                        break;
    +
    +                    default:
    +                        throw new IllegalArgumentException("key must be 16, 24 or 32 bytes");
    +                }
    +
    +                CryptoServicesRegistrar.checkConstraints(
    +                        new DefaultServiceProperties(
    +                                getAlgorithmName(),
    +                                key.length * 8,
    +                                params,
    +                                forEncryption ? CryptoServicePurpose.ENCRYPTION : CryptoServicePurpose.DECRYPTION
    +                        ));
    +
    +
    +                init(wrapper.getReference(), key);
    +
    +                keyLen = key.length * 8;
    +
    +                return;
    +
    +            }
    +
    +
    +            throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public String getAlgorithmName()
    +    {
    +        return "AES";
    +    }
    +
    +    @Override
    +    public int getBlockSize()
    +    {
    +        return getBlockSize(0);
    +    }
    +
    +    @Override
    +    public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
    +            throws DataLengthException, IllegalStateException
    +    {
    +        try
    +        {
    +            if (wrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +
    +            return process(wrapper.getReference(), in, inOff, 1, out, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int getMultiBlockSize()
    +    {
    +        return getMultiBlockSize(0);
    +    }
    +
    +
    +    @Override
    +    public int processBlocks(byte[] in, int inOff, int blockCount, byte[] out, int outOff)
    +            throws DataLengthException, IllegalStateException
    +    {
    +
    +        try
    +        {
    +            if (wrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +
    +
    +            return process(wrapper.getReference(), in, inOff, blockCount, out, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public void reset()
    +    {
    +        try
    +        {
    +            // skip over spurious resets that may occur before init is called.
    +            if (wrapper == null)
    +            {
    +                return;
    +            }
    +            reset(wrapper.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public GCMModeCipher createGCM()
    +    {
    +        if (CryptoServicesRegistrar.hasEnabledService(NativeServices.AES_GCM))
    +        {
    +            return new AESNativeGCM();
    +        }
    +
    +        return new GCMBlockCipher(new AESEngine());
    +    }
    +
    +    @Override
    +    public GCMSIVModeCipher createGCMSIV()
    +    {
    +        if (CryptoServicesRegistrar.hasEnabledService(NativeServices.AES_GCMSIV))
    +        {
    +            return new AESNativeGCMSIV();
    +        }
    +        return new GCMSIVBlockCipher(new AESNativeEngine());
    +    }
    +
    +    @Override
    +    public CBCModeCipher createCBC()
    +    {
    +        if (CryptoServicesRegistrar.hasEnabledService(NativeServices.AES_CBC))
    +        {
    +            return new AESNativeCBC();
    +        }
    +        return new CBCBlockCipher(new AESNativeEngine());
    +    }
    +
    +    @Override
    +    public CFBModeCipher createCFB(int bitSize)
    +    {
    +        if (bitSize % 8 != 0 || bitSize == 0 || bitSize > 128)
    +        {
    +            throw new IllegalArgumentException("invalid CFB bitsize: " + bitSize);
    +        }
    +
    +        if (CryptoServicesRegistrar.hasEnabledService(NativeServices.AES_CFB))
    +        {
    +            return new AESNativeCFB(bitSize);
    +        }
    +
    +        return new CFBBlockCipher(new AESNativeEngine(), bitSize);
    +    }
    +
    +
    +    @Override
    +    public CTRModeCipher createCTR()
    +    {
    +        if (CryptoServicesRegistrar.hasEnabledService(NativeServices.AES_CTR))
    +        {
    +            return new AESNativeCTR();
    +        }
    +
    +        return new SICBlockCipher(AESEngine.newInstance());
    +    }
    +
    +    @Override
    +    public CCMModeCipher createCCM()
    +    {
    +        if (CryptoServicesRegistrar.hasEnabledService(NativeServices.AES_CCM))
    +        {
    +            return new AESNativeCCM();
    +        }
    +
    +        return new CCMBlockCipher(AESEngine.newInstance());
    +    }
    +
    +    @Override
    +    public EAXModeCipher createEAX()
    +    {
    +        return new EAXBlockCipher(AESEngine.newInstance());
    +    }
    +
    +    @Override
    +    public OCBModeCipher createOCB()
    +    {
    +        return new OCBBlockCipher(AESEngine.newInstance(), AESEngine.newInstance());
    +    }
    +
    +    private static class Disposer
    +            extends NativeDisposer
    +    {
    +        Disposer(long ref)
    +        {
    +            super(ref);
    +        }
    +
    +        @Override
    +        protected void dispose(long reference)
    +        {
    +            AESNativeEngine.dispose(reference);
    +        }
    +    }
    +
    +    private static class ECBNativeRef
    +            extends NativeReference
    +    {
    +
    +        public ECBNativeRef(long reference)
    +        {
    +            super(reference, "ECB");
    +        }
    +
    +        @Override
    +        protected Runnable createAction()
    +        {
    +            return new Disposer(reference);
    +        }
    +    }
    +
    +    public String toString()
    +    {
    +        return "AES[Native](" + keyLen + ")";
    +    }
    +
    +    private static native void reset(long ref);
    +
    +    private static native int process(long ref, byte[] in, int inOff, int blocks, byte[] out, int outOff);
    +
    +    private static native int getMultiBlockSize(long nativeRef);
    +
    +    private static native int getBlockSize(long ref);
    +
    +    static native long makeInstance(int length, boolean forEncryption);
    +
    +    static native void dispose(long ref);
    +
    +    static native void init(long nativeRef, byte[] key);
    +}
    
  • core/src/main/java9/org/bouncycastle/crypto/engines/AESNativeGCM.java+477 0 added
    @@ -0,0 +1,477 @@
    +package org.bouncycastle.crypto.engines;
    +
    +import org.bouncycastle.crypto.BlockCipher;
    +import org.bouncycastle.crypto.CipherParameters;
    +import org.bouncycastle.crypto.DataLengthException;
    +import org.bouncycastle.crypto.InvalidCipherTextException;
    +import org.bouncycastle.crypto.modes.GCMModeCipher;
    +import org.bouncycastle.crypto.params.AEADParameters;
    +import org.bouncycastle.crypto.params.KeyParameter;
    +import org.bouncycastle.crypto.params.ParametersWithIV;
    +import org.bouncycastle.util.Arrays;
    +import org.bouncycastle.util.dispose.NativeDisposer;
    +import org.bouncycastle.util.dispose.NativeReference;
    +
    +import java.lang.ref.Reference;
    +
    +class AESNativeGCM
    +        implements GCMModeCipher
    +{
    +    private GCMRefWrapper refWrapper;
    +    private byte[] oldNonce;
    +    private boolean forEncryption = false;
    +    private boolean initialised = false;
    +    private byte[] keptMac = null;
    +
    +
    +    @Override
    +    public BlockCipher getUnderlyingCipher()
    +    {
    +        try
    +        {
    +            BlockCipher engine = AESEngine.newInstance();
    +            if (refWrapper != null && refWrapper.key != null)
    +            {
    +                engine.init(true, new KeyParameter(refWrapper.key));
    +            }
    +            return engine;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    public void init(boolean forEncryption, CipherParameters params)
    +            throws IllegalArgumentException
    +    {
    +        try
    +        {
    +            this.forEncryption = forEncryption;
    +            KeyParameter keyParam;
    +            byte[] newNonce = null;
    +            keptMac = null;
    +            int macSize;
    +            byte[] initialAssociatedText;
    +
    +            if (params instanceof AEADParameters)
    +            {
    +                AEADParameters param = (AEADParameters) params;
    +
    +                newNonce = param.getNonce();
    +                initialAssociatedText = param.getAssociatedText();
    +
    +                int macSizeBits = param.getMacSize();
    +                if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0)
    +                {
    +                    throw new IllegalArgumentException("invalid value for MAC size: " + macSizeBits);
    +                }
    +
    +                macSize = macSizeBits;
    +                keyParam = param.getKey();
    +            }
    +            else if (params instanceof ParametersWithIV)
    +            {
    +                ParametersWithIV param = (ParametersWithIV) params;
    +
    +                newNonce = param.getIV();
    +                initialAssociatedText = null;
    +                macSize = 128;
    +                keyParam = (KeyParameter) param.getParameters();
    +            }
    +            else
    +            {
    +                throw new IllegalArgumentException("invalid parameters passed to GCM");
    +            }
    +
    +            if (newNonce == null || newNonce.length < 12)
    +            {
    +                throw new IllegalArgumentException("IV must be at least 12 bytes");
    +            }
    +
    +            byte[] key = null;
    +
    +            if (forEncryption)
    +            {
    +                if (oldNonce != null && Arrays.areEqual(oldNonce, newNonce))
    +                {
    +                    if (keyParam == null)
    +                    {
    +                        throw new IllegalArgumentException("cannot reuse nonce for GCM encryption");
    +                    }
    +
    +                    if (refWrapper != null && refWrapper.key != null && Arrays.areEqual(refWrapper.key, keyParam.getKey()))
    +                    {
    +                        // same nonce, same key
    +                        throw new IllegalArgumentException("cannot reuse nonce for GCM encryption");
    +                    }
    +
    +                    if (refWrapper != null && refWrapper.key != null)
    +                    {
    +                        key = Arrays.clone(refWrapper.key); // Case keyParam is null
    +                    }
    +                }
    +            }
    +
    +            oldNonce = newNonce;
    +
    +            if (keyParam != null)
    +            {
    +                key = keyParam.getKey();
    +                switch (key.length)
    +                {
    +                    case 16:
    +                    case 24:
    +                    case 32:
    +                        break;
    +                    default:
    +                        throw new IllegalStateException("key must be only 16,24,or 32 bytes long.");
    +                }
    +            }
    +
    +            initRef(key);
    +
    +            initNative(
    +                    refWrapper.getReference(),
    +                    forEncryption, key,
    +                    oldNonce, initialAssociatedText, macSize);
    +
    +
    +            initialised = true;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    private void initRef(byte[] key)
    +    {
    +        try
    +        {
    +            refWrapper = new GCMRefWrapper(makeInstance(key.length, forEncryption), key);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public String getAlgorithmName()
    +    {
    +        return "AES/GCM";
    +    }
    +
    +    @Override
    +    public void processAADByte(byte in)
    +    {
    +        try
    +        {
    +            processAADByte(refWrapper.getReference(), in);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void processAADBytes(byte[] in, int inOff, int len)
    +    {
    +
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException("GCM is uninitialized");
    +            }
    +
    +            processAADBytes(refWrapper.getReference(), in, inOff, len);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int processByte(byte in, byte[] out, int outOff)
    +            throws DataLengthException
    +    {
    +
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException("GCM is uninitialized");
    +            }
    +
    +            return processByte(refWrapper.getReference(), in, out, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
    +            throws DataLengthException
    +    {
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException("GCM is uninitialized");
    +            }
    +
    +            return processBytes(refWrapper.getReference(), in, inOff, len, out, outOff);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int doFinal(byte[] out, int outOff)
    +            throws IllegalStateException, InvalidCipherTextException
    +    {
    +
    +        try
    +        {
    +            checkStatus();
    +
    +
    +            int len = doFinal(refWrapper.getReference(), out, outOff);
    +
    +            //
    +            // BlockCipherTest, testing ShortTagException.
    +            //
    +
    +            resetKeepMac();
    +            return len;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public byte[] getMac()
    +    {
    +        try
    +        {
    +            if (keptMac != null)
    +            {
    +                return Arrays.clone(keptMac);
    +            }
    +            return getMac(refWrapper.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int getUpdateOutputSize(int len)
    +    {
    +        try
    +        {
    +            return getUpdateOutputSize(refWrapper.getReference(), len);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public int getOutputSize(int len)
    +    {
    +        try
    +        {
    +            return getOutputSize(refWrapper.getReference(), len);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void reset()
    +    {
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                // deal with reset being called before init.
    +                return;
    +            }
    +
    +            reset(refWrapper.getReference());
    +            initialised = false;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    private void resetKeepMac()
    +    {
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                // deal with reset being called before init.
    +                return;
    +            }
    +
    +            keptMac = getMac();
    +            reset(refWrapper.getReference());
    +            initialised = false;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    private void checkStatus()
    +    {
    +        if (!initialised)
    +        {
    +            if (forEncryption)
    +            {
    +                throw new IllegalStateException("GCM cipher cannot be reused for encryption");
    +            }
    +            throw new IllegalStateException("GCM cipher needs to be initialised");
    +        }
    +    }
    +
    +    private native void reset(long ref);
    +
    +    static native void initNative(
    +            long reference,
    +            boolean forEncryption,
    +            byte[] keyParam,
    +            byte[] nonce,
    +            byte[] initialAssociatedText,
    +            int macSizeBits);
    +
    +    static native long makeInstance(int keySize, boolean forEncryption);
    +
    +    static native void dispose(long nativeRef);
    +
    +    private static native void processAADByte(long ref, byte in);
    +
    +    private static native void processAADBytes(long ref, byte[] in, int inOff, int len);
    +
    +    private static native int processByte(long ref, byte in, byte[] out, int outOff);
    +
    +    private static native int processBytes(long ref, byte[] in, int inOff, int len, byte[] out, int outOff);
    +
    +    private static native int doFinal(long ref, byte[] out, int outOff);
    +
    +    private static native int getUpdateOutputSize(long ref, int len);
    +
    +    private static native int getOutputSize(long ref, int len);
    +
    +    public static native byte[] getMac(long ref);
    +
    +    /**
    +     * Set blocks remaining but only to a lesser value and only if the transformation has processed no data.
    +     * Functionality limited to within the module only.
    +     *
    +     * @param value the step value.
    +     */
    +    void setBlocksRemainingDown(long value)
    +    {
    +        try
    +        {
    +            setBlocksRemainingDown(refWrapper.getReference(), value);
    +        } finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    // Set the blocks remaining, but only to a lesser value.
    +    // This is intended for testing only and will throw from the native side if the
    +    // transformation has processed any data.
    +    private native void setBlocksRemainingDown(long nativeRef, long value);
    +
    +
    +    private static class GCMRefWrapper
    +            extends NativeReference
    +    {
    +        private final byte[] key;
    +
    +        public GCMRefWrapper(long reference, byte[] key)
    +        {
    +            super(reference, "GCM");
    +            this.key = key;
    +        }
    +
    +        @Override
    +        public Runnable createAction()
    +        {
    +            return new Disposer(reference, key);
    +        }
    +
    +    }
    +
    +
    +    private static class Disposer
    +            extends NativeDisposer
    +    {
    +        private final byte[] key;
    +
    +        Disposer(long ref, byte[] key)
    +        {
    +            super(ref);
    +            this.key = key;
    +        }
    +
    +        @Override
    +        protected void dispose(long reference)
    +        {
    +            Arrays.clear(key);
    +            AESNativeGCM.dispose(reference);
    +        }
    +    }
    +
    +    @Override
    +    public String toString()
    +    {
    +        try
    +        {
    +            if (refWrapper.key != null)
    +            {
    +                return "GCM[Native](AES[Native](" + (refWrapper.key.length * 8) + "))";
    +            }
    +            return "GCM[Native](AES[Native](not initialized))";
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +}
    
  • core/src/main/java9/org/bouncycastle/crypto/engines/AESNativeGCMSIV.java+423 0 added
    @@ -0,0 +1,423 @@
    +package org.bouncycastle.crypto.engines;
    +
    +import org.bouncycastle.crypto.*;
    +import org.bouncycastle.crypto.modes.GCMSIVModeCipher;
    +import org.bouncycastle.crypto.params.AEADParameters;
    +import org.bouncycastle.crypto.params.KeyParameter;
    +import org.bouncycastle.crypto.params.ParametersWithIV;
    +import org.bouncycastle.util.Arrays;
    +import org.bouncycastle.util.dispose.NativeDisposer;
    +import org.bouncycastle.util.dispose.NativeReference;
    +
    +import java.io.ByteArrayOutputStream;
    +import java.lang.ref.Reference;
    +
    +public class AESNativeGCMSIV
    +        implements GCMSIVModeCipher
    +{
    +    private GCMSIVRefWrapper refWrapper;
    +    private byte[] keptMac;
    +
    +    /**
    +     * The encryptedDataStream
    +     */
    +    private final GCMSIVCache theEncData = new GCMSIVCache();
    +
    +    /**
    +     * Are we encrypting?
    +     */
    +    private boolean forEncryption;
    +
    +
    +    /**
    +     * The nonce.
    +     */
    +    private byte[] theNonce;
    +    private byte[] theInitialAEAD;
    +
    +
    +    @Override
    +    public BlockCipher getUnderlyingCipher()
    +    {
    +        try
    +        {
    +            BlockCipher engine = AESEngine.newInstance();
    +            if (refWrapper != null && refWrapper.key != null)
    +            {
    +                engine.init(true, new KeyParameter(refWrapper.key));
    +            }
    +            return engine;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public void init(boolean forEncryption, CipherParameters cipherParameters)
    +            throws IllegalArgumentException
    +    {
    +        try
    +        {
    +            this.forEncryption = forEncryption;
    +            keptMac = null;
    +            theEncData.reset();
    +
    +            /* Set defaults */
    +            byte[] myInitialAEAD = null;
    +            byte[] myNonce;
    +            KeyParameter myKey;
    +
    +            /* Access parameters */
    +            if (cipherParameters instanceof AEADParameters)
    +            {
    +                final AEADParameters myAEAD = (AEADParameters) cipherParameters;
    +                myInitialAEAD = myAEAD.getAssociatedText();
    +                myNonce = myAEAD.getNonce();
    +                myKey = myAEAD.getKey();
    +            }
    +            else if (cipherParameters instanceof ParametersWithIV)
    +            {
    +                final ParametersWithIV myParms = (ParametersWithIV) cipherParameters;
    +                myNonce = myParms.getIV();
    +                myKey = (KeyParameter) myParms.getParameters();
    +            }
    +            else
    +            {
    +                throw new IllegalArgumentException("invalid parameters passed to GCM-SIV");
    +            }
    +
    +            /* Reset details */
    +            /**
    +             * The initialAEAD.
    +             */
    +            theInitialAEAD = myInitialAEAD;
    +            theNonce = myNonce;
    +            byte[] keyBytes = myKey.getKey();
    +            switch (keyBytes.length)
    +            {
    +                case 16:
    +                case 24:
    +                case 32:
    +                    break;
    +                default:
    +                    throw new IllegalStateException(ExceptionMessages.AES_KEY_LENGTH);
    +            }
    +
    +            initRef(keyBytes);
    +
    +
    +            initNative(
    +                    refWrapper.getReference(),
    +                    forEncryption, refWrapper.key,
    +                    theNonce, theInitialAEAD);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    private void initRef(byte[] key)
    +    {
    +        refWrapper = new GCMSIVRefWrapper(makeInstance(), key);
    +    }
    +
    +    @Override
    +    public String getAlgorithmName()
    +    {
    +        return "AES/GCM-SIV";
    +    }
    +
    +    @Override
    +    public void processAADByte(byte in)
    +    {
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +            processAADByte(refWrapper.getReference(), in);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public void processAADBytes(byte[] in, int inOff, int len)
    +    {
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +            processAADBytes(refWrapper.getReference(), in, inOff, len);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int processByte(byte in, byte[] out, int outOff)
    +            throws DataLengthException
    +    {
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +            theEncData.write(in);
    +            return 0;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
    +            throws DataLengthException
    +    {
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +            theEncData.write(in, inOff, len);
    +            return 0;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int doFinal(byte[] out, int outOff)
    +            throws IllegalStateException, InvalidCipherTextException
    +    {
    +
    +        try
    +        {
    +            int len = doFinal(refWrapper.getReference(), theEncData.getBuffer(), theEncData.size(), out, outOff);
    +            //resetKeepMac
    +            keptMac = getMac();
    +            reset();
    +            return len;
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public byte[] getMac()
    +    {
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +
    +            if (keptMac != null)
    +            {
    +                return Arrays.clone(keptMac);
    +            }
    +            return getMac(refWrapper.getReference());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int getUpdateOutputSize(int len)
    +    {
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +            return getUpdateOutputSize(refWrapper.getReference(), len, theEncData.size());
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    @Override
    +    public int getOutputSize(int len)
    +    {
    +        try
    +        {
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +            return getOutputSize(refWrapper.getReference(), len);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +
    +    @Override
    +    public void reset()
    +    {
    +        try
    +        {
    +            theEncData.clearBuffer();
    +            if (refWrapper == null)
    +            {
    +                // deal with reset being called before init.
    +                return;
    +            }
    +            reset(refWrapper.getReference());
    +            initNative(
    +                    refWrapper.getReference(),
    +                    forEncryption, refWrapper.key,
    +                    theNonce, theInitialAEAD);
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    public String toString()
    +    {
    +        try
    +        {
    +            if (refWrapper != null && refWrapper.key != null)
    +            {
    +                return "GCMSIV[Native](AES[Native](" + (refWrapper.key.length * 8) + "))";
    +            }
    +            return "GCMSIV[Native](AES[Native](not initialized))";
    +        }
    +        finally
    +        {
    +            Reference.reachabilityFence(this);
    +        }
    +    }
    +
    +    private static class GCMSIVRefWrapper
    +            extends NativeReference
    +    {
    +        private final byte[] key;
    +
    +        public GCMSIVRefWrapper(long reference, byte[] key)
    +        {
    +            super(reference, "GCM-SIV");
    +            this.key = key;
    +        }
    +
    +        @Override
    +        public Runnable createAction()
    +        {
    +            return new Disposer(reference, key);
    +        }
    +
    +    }
    +
    +    private static class Disposer
    +            extends NativeDisposer
    +    {
    +        private final byte[] key;
    +
    +        Disposer(long ref, byte[] key)
    +        {
    +            super(ref);
    +            this.key = key;
    +        }
    +
    +        @Override
    +        protected void dispose(long reference)
    +        {
    +            Arrays.clear(key);
    +            AESNativeGCMSIV.dispose(reference);
    +        }
    +    }
    +
    +    private native void reset(long ref);
    +
    +    static native void initNative(
    +            long reference,
    +            boolean forEncryption,
    +            byte[] keyParam,
    +            byte[] nonce,
    +            byte[] initialAssociatedText);
    +
    +    static native long makeInstance();
    +
    +    static native void dispose(long nativeRef);
    +
    +    static native void processAADByte(long ref, byte in);
    +
    +    static native void processAADBytes(long ref, byte[] in, int inOff, int len);
    +
    +    static native int doFinal(long ref, byte[] input, int inputLen, byte[] out, int outOff);
    +
    +    static native int getUpdateOutputSize(long ref, int len, int streamLen);
    +
    +    static native int getOutputSize(long ref, int len);
    +
    +    static native byte[] getMac(long ref);
    +
    +    /**
    +     * Test method, you have ABSOLUTELY no reason to call this in normal use.
    +     * max_dl is the maximum amount of data the implementation will process.
    +     */
    +    static native void test_set_max_dl(long ref, long value);
    +
    +
    +    /**
    +     * GCMSIVCache.
    +     */
    +    private static class GCMSIVCache
    +            extends ByteArrayOutputStream
    +    {
    +        /**
    +         * Constructor.
    +         */
    +        GCMSIVCache()
    +        {
    +        }
    +
    +        /**
    +         * Obtain the buffer.
    +         *
    +         * @return the buffer
    +         */
    +        byte[] getBuffer()
    +        {
    +            return this.buf;
    +        }
    +
    +        /**
    +         * Clear the buffer.
    +         */
    +        void clearBuffer()
    +        {
    +            Arrays.fill(getBuffer(), (byte) 0);
    +            reset();
    +        }
    +    }
    +
    +}
    
  • core/src/main/java/org/bouncycastle/crypto/DefaultBufferedBlockCipher.java+6 6 modified
    @@ -243,12 +243,12 @@ public int processBytes(
                     len -= gapLen;
                 }
     
    -            if (in == out && Arrays.segmentsOverlap(inOff, len, outOff, length))
    -            {
    -                in = new byte[len];
    -                System.arraycopy(out, inOff, in, 0, len);
    -                inOff = 0;
    -            }
    +//            if (in == out && Arrays.segmentsOverlap(inOff, len, outOff, length))
    +//            {
    +//                in = new byte[len];
    +//                System.arraycopy(out, inOff, in, 0, len);
    +//                inOff = 0;
    +//            }
     
                 // if bufOff non-zero buffer must now be full
                 if (bufOff != 0)
    
  • core/src/main/java/org/bouncycastle/crypto/digests/SHA224NativeDigest.java+46 17 modified
    @@ -47,8 +47,11 @@ class SHA224NativeDigest
     
         SHA224NativeDigest restoreState(byte[] state, int offset)
         {
    -        restoreFullState(nativeRef.getReference(), state, offset);
    -        return this;
    +        synchronized (this)
    +        {
    +            restoreFullState(nativeRef.getReference(), state, offset);
    +            return this;
    +        }
         }
     
         //
    @@ -64,43 +67,60 @@ public String getAlgorithmName()
         @Override
         public int getDigestSize()
         {
    -        return getDigestSize(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            return getDigestSize(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public void update(byte in)
         {
    -
    -        update(nativeRef.getReference(), in);
    +        synchronized (this)
    +        {
    +            update(nativeRef.getReference(), in);
    +        }
         }
     
     
         @Override
         public void update(byte[] input, int inOff, int len)
         {
    -        update(nativeRef.getReference(), input, inOff, len);
    +        synchronized (this)
    +        {
    +            update(nativeRef.getReference(), input, inOff, len);
    +        }
         }
     
     
         @Override
         public int doFinal(byte[] output, int outOff)
         {
    -        return doFinal(nativeRef.getReference(), output, outOff);
    +        synchronized (this)
    +        {
    +            return doFinal(nativeRef.getReference(), output, outOff);
    +        }
         }
     
     
         @Override
         public void reset()
         {
    -        reset(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            reset(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public int getByteLength()
         {
    -        return getByteLength(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            return getByteLength(nativeRef.getReference());
    +        }
         }
     
     
    @@ -113,23 +133,32 @@ public Memoable copy()
         @Override
         public void reset(Memoable other)
         {
    -        SHA224NativeDigest dig = (SHA224NativeDigest) other;
    -        restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        synchronized (this)
    +        {
    +            SHA224NativeDigest dig = (SHA224NativeDigest) other;
    +            restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        }
         }
     
     
         public byte[] getEncodedState()
         {
    -        int l = encodeFullState(nativeRef.getReference(), null, 0);
    -        byte[] state = new byte[l];
    -        encodeFullState(nativeRef.getReference(), state, 0);
    -        return state;
    +        synchronized (this)
    +        {
    +            int l = encodeFullState(nativeRef.getReference(), null, 0);
    +            byte[] state = new byte[l];
    +            encodeFullState(nativeRef.getReference(), state, 0);
    +            return state;
    +        }
         }
     
     
         void restoreFullState(byte[] encoded, int offset)
         {
    -        restoreFullState(nativeRef.getReference(), encoded, offset);
    +        synchronized (this)
    +        {
    +            restoreFullState(nativeRef.getReference(), encoded, offset);
    +        }
         }
     
     
    @@ -187,7 +216,7 @@ private static class DigestRefWrapper
     
             public DigestRefWrapper(long reference)
             {
    -            super(reference,"SHA224");
    +            super(reference, "SHA224");
             }
     
             @Override
    
  • core/src/main/java/org/bouncycastle/crypto/digests/SHA256NativeDigest.java+51 22 modified
    @@ -16,7 +16,7 @@ class SHA256NativeDigest
     {
         private final CryptoServicePurpose purpose;
     
    -    protected DigestRefWrapper nativeRef = null;
    +    private DigestRefWrapper nativeRef = null;
     
         SHA256NativeDigest(CryptoServicePurpose purpose)
         {
    @@ -47,8 +47,11 @@ class SHA256NativeDigest
     
         SHA256NativeDigest restoreState(byte[] state, int offset)
         {
    -        restoreFullState(nativeRef.getReference(), state, offset);
    -        return this;
    +        synchronized (this)
    +        {
    +            restoreFullState(nativeRef.getReference(), state, offset);
    +            return this;
    +        }
         }
     
         //
    @@ -64,78 +67,104 @@ public String getAlgorithmName()
         @Override
         public int getDigestSize()
         {
    -        return getDigestSize(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            return getDigestSize(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public void update(byte in)
         {
    -
    -        update(nativeRef.getReference(), in);
    +        synchronized (this)
    +        {
    +            update(nativeRef.getReference(), in);
    +        }
         }
     
     
         @Override
         public void update(byte[] input, int inOff, int len)
         {
    -        update(nativeRef.getReference(), input, inOff, len);
    +        synchronized (this)
    +        {
    +            update(nativeRef.getReference(), input, inOff, len);
    +        }
         }
     
     
         @Override
         public int doFinal(byte[] output, int outOff)
         {
    -        return doFinal(nativeRef.getReference(), output, outOff);
    +        synchronized (this)
    +        {
    +            return doFinal(nativeRef.getReference(), output, outOff);
    +        }
         }
     
     
         @Override
         public void reset()
         {
    -        reset(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            reset(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public int getByteLength()
         {
    -        return getByteLength(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            return getByteLength(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public Memoable copy()
         {
    -        return new SHA256NativeDigest(this);
    +        synchronized (this)
    +        {
    +            return new SHA256NativeDigest(this);
    +        }
         }
     
         @Override
         public void reset(Memoable other)
         {
    -        SHA256NativeDigest dig = (SHA256NativeDigest) other;
    -        restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        synchronized (this)
    +        {
    +            SHA256NativeDigest dig = (SHA256NativeDigest) other;
    +            restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        }
         }
     
     
         public byte[] getEncodedState()
         {
    -        int l = encodeFullState(nativeRef.getReference(), null, 0);
    -        byte[] state = new byte[l];
    -        encodeFullState(nativeRef.getReference(), state, 0);
    -        return state;
    +        synchronized (this)
    +        {
    +            int l = encodeFullState(nativeRef.getReference(), null, 0);
    +            byte[] state = new byte[l];
    +            encodeFullState(nativeRef.getReference(), state, 0);
    +            return state;
    +        }
         }
     
     
    -
    -
         void restoreFullState(byte[] encoded, int offset)
         {
    -        restoreFullState(nativeRef.getReference(), encoded, offset);
    +        synchronized (this)
    +        {
    +            restoreFullState(nativeRef.getReference(), encoded, offset);
    +        }
         }
     
     
    -
         @Override
         public String toString()
         {
    @@ -190,7 +219,7 @@ private static class DigestRefWrapper
     
             public DigestRefWrapper(long reference)
             {
    -            super(reference,"SHA256");
    +            super(reference, "SHA256");
             }
     
             @Override
    
  • core/src/main/java/org/bouncycastle/crypto/digests/SHA384NativeDigest.java+50 21 modified
    @@ -47,8 +47,11 @@ class SHA384NativeDigest
     
         SHA384NativeDigest restoreState(byte[] state, int offset)
         {
    -        restoreFullState(nativeRef.getReference(), state, offset);
    -        return this;
    +        synchronized (this)
    +        {
    +            restoreFullState(nativeRef.getReference(), state, offset);
    +            return this;
    +        }
         }
     
         //
    @@ -64,78 +67,104 @@ public String getAlgorithmName()
         @Override
         public int getDigestSize()
         {
    -        return getDigestSize(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            return getDigestSize(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public void update(byte in)
         {
    -
    -        update(nativeRef.getReference(), in);
    +        synchronized (this)
    +        {
    +            update(nativeRef.getReference(), in);
    +        }
         }
     
     
         @Override
         public void update(byte[] input, int inOff, int len)
         {
    -        update(nativeRef.getReference(), input, inOff, len);
    +        synchronized (this)
    +        {
    +            update(nativeRef.getReference(), input, inOff, len);
    +        }
         }
     
     
         @Override
         public int doFinal(byte[] output, int outOff)
         {
    -        return doFinal(nativeRef.getReference(), output, outOff);
    +        synchronized (this)
    +        {
    +            return doFinal(nativeRef.getReference(), output, outOff);
    +        }
         }
     
     
         @Override
         public void reset()
         {
    -        reset(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            reset(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public int getByteLength()
         {
    -        return getByteLength(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            return getByteLength(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public Memoable copy()
         {
    -        return new SHA384NativeDigest(this);
    +        synchronized (this)
    +        {
    +            return new SHA384NativeDigest(this);
    +        }
         }
     
         @Override
         public void reset(Memoable other)
         {
    -        SHA384NativeDigest dig = (SHA384NativeDigest) other;
    -        restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        synchronized (this)
    +        {
    +            SHA384NativeDigest dig = (SHA384NativeDigest) other;
    +            restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        }
         }
     
     
         public byte[] getEncodedState()
         {
    -        int l = encodeFullState(nativeRef.getReference(), null, 0);
    -        byte[] state = new byte[l];
    -        encodeFullState(nativeRef.getReference(), state, 0);
    -        return state;
    +        synchronized (this)
    +        {
    +            int l = encodeFullState(nativeRef.getReference(), null, 0);
    +            byte[] state = new byte[l];
    +            encodeFullState(nativeRef.getReference(), state, 0);
    +            return state;
    +        }
         }
     
     
    -
    -
         void restoreFullState(byte[] encoded, int offset)
         {
    -        restoreFullState(nativeRef.getReference(), encoded, offset);
    +        synchronized (this)
    +        {
    +            restoreFullState(nativeRef.getReference(), encoded, offset);
    +        }
         }
     
     
    -
         @Override
         public String toString()
         {
    @@ -190,7 +219,7 @@ private static class DigestRefWrapper
     
             public DigestRefWrapper(long reference)
             {
    -            super(reference,"SHA384");
    +            super(reference, "SHA384");
             }
     
             @Override
    
  • core/src/main/java/org/bouncycastle/crypto/digests/SHA3NativeDigest.java+49 19 modified
    @@ -17,12 +17,12 @@ public class SHA3NativeDigest
         private int bitLen;
     
     
    -  public   SHA3NativeDigest(CryptoServicePurpose purpose)
    +    public SHA3NativeDigest(CryptoServicePurpose purpose)
         {
             this(256, purpose);
         }
     
    -   public  SHA3NativeDigest(int bitLen, CryptoServicePurpose purpose)
    +    public SHA3NativeDigest(int bitLen, CryptoServicePurpose purpose)
         {
             if (!CryptoServicesRegistrar.hasEnabledService(NativeServices.SHA3))
             {
    @@ -71,8 +71,11 @@ public SHA3NativeDigest(byte[] encoded)
     
         SHA3NativeDigest restoreState(byte[] state, int offset)
         {
    -        restoreFullState(nativeRef.getReference(), state, offset);
    -        return this;
    +        synchronized (this)
    +        {
    +            restoreFullState(nativeRef.getReference(), state, offset);
    +            return this;
    +        }
         }
     
         //
    @@ -89,44 +92,62 @@ public String getAlgorithmName()
         @Override
         public int getDigestSize()
         {
    -        return getDigestSize(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            return getDigestSize(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public void update(byte in)
         {
    -        update(nativeRef.getReference(), in);
    +        synchronized (this)
    +        {
    +            update(nativeRef.getReference(), in);
    +        }
         }
     
     
         @Override
         public void update(byte[] input, int inOff, int len)
         {
    -        update(nativeRef.getReference(), input, inOff, len);
    +        synchronized (this)
    +        {
    +            update(nativeRef.getReference(), input, inOff, len);
    +        }
         }
     
     
         @Override
         public int doFinal(byte[] output, int outOff)
         {
    -        int i = doFinal(nativeRef.getReference(), output, outOff);
    -        reset();
    -        return i;
    +        synchronized (this)
    +        {
    +            int i = doFinal(nativeRef.getReference(), output, outOff);
    +            reset();
    +            return i;
    +        }
         }
     
     
         @Override
         public void reset()
         {
    -        reset(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            reset(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public int getByteLength()
         {
    -        return getByteLength(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            return getByteLength(nativeRef.getReference());
    +        }
         }
     
     
    @@ -139,23 +160,32 @@ public Memoable copy()
         @Override
         public void reset(Memoable other)
         {
    -        SHA3NativeDigest dig = (SHA3NativeDigest) other;
    -        restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        synchronized (this)
    +        {
    +            SHA3NativeDigest dig = (SHA3NativeDigest) other;
    +            restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        }
         }
     
     
         public byte[] getEncodedState()
         {
    -        int l = encodeFullState(nativeRef.getReference(), null, 0);
    -        byte[] state = new byte[l];
    -        encodeFullState(nativeRef.getReference(), state, 0);
    -        return state;
    +        synchronized (this)
    +        {
    +            int l = encodeFullState(nativeRef.getReference(), null, 0);
    +            byte[] state = new byte[l];
    +            encodeFullState(nativeRef.getReference(), state, 0);
    +            return state;
    +        }
         }
     
     
         void restoreFullState(byte[] encoded, int offset)
         {
    -        restoreFullState(nativeRef.getReference(), encoded, offset);
    +        synchronized (this)
    +        {
    +            restoreFullState(nativeRef.getReference(), encoded, offset);
    +        }
         }
     
     
    
  • core/src/main/java/org/bouncycastle/crypto/digests/SHA512NativeDigest.java+50 21 modified
    @@ -47,8 +47,11 @@ class SHA512NativeDigest
     
         SHA512NativeDigest restoreState(byte[] state, int offset)
         {
    -        restoreFullState(nativeRef.getReference(), state, offset);
    -        return this;
    +        synchronized (this)
    +        {
    +            restoreFullState(nativeRef.getReference(), state, offset);
    +            return this;
    +        }
         }
     
         //
    @@ -64,78 +67,104 @@ public String getAlgorithmName()
         @Override
         public int getDigestSize()
         {
    -        return getDigestSize(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            return getDigestSize(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public void update(byte in)
         {
    -
    -        update(nativeRef.getReference(), in);
    +        synchronized (this)
    +        {
    +            update(nativeRef.getReference(), in);
    +        }
         }
     
     
         @Override
         public void update(byte[] input, int inOff, int len)
         {
    -        update(nativeRef.getReference(), input, inOff, len);
    +        synchronized (this)
    +        {
    +            update(nativeRef.getReference(), input, inOff, len);
    +        }
         }
     
     
         @Override
         public int doFinal(byte[] output, int outOff)
         {
    -        return doFinal(nativeRef.getReference(), output, outOff);
    +        synchronized (this)
    +        {
    +            return doFinal(nativeRef.getReference(), output, outOff);
    +        }
         }
     
     
         @Override
         public void reset()
         {
    -        reset(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            reset(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public int getByteLength()
         {
    -        return getByteLength(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            return getByteLength(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public Memoable copy()
         {
    -        return new SHA512NativeDigest(this);
    +        synchronized (this)
    +        {
    +            return new SHA512NativeDigest(this);
    +        }
         }
     
         @Override
         public void reset(Memoable other)
         {
    -        SHA512NativeDigest dig = (SHA512NativeDigest) other;
    -        restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        synchronized (this)
    +        {
    +            SHA512NativeDigest dig = (SHA512NativeDigest) other;
    +            restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        }
         }
     
     
         public byte[] getEncodedState()
         {
    -        int l = encodeFullState(nativeRef.getReference(), null, 0);
    -        byte[] state = new byte[l];
    -        encodeFullState(nativeRef.getReference(), state, 0);
    -        return state;
    +        synchronized (this)
    +        {
    +            int l = encodeFullState(nativeRef.getReference(), null, 0);
    +            byte[] state = new byte[l];
    +            encodeFullState(nativeRef.getReference(), state, 0);
    +            return state;
    +        }
         }
     
     
    -
    -
         void restoreFullState(byte[] encoded, int offset)
         {
    -        restoreFullState(nativeRef.getReference(), encoded, offset);
    +        synchronized (this)
    +        {
    +            restoreFullState(nativeRef.getReference(), encoded, offset);
    +        }
         }
     
     
    -
         @Override
         public String toString()
         {
    @@ -190,7 +219,7 @@ private static class DigestRefWrapper
     
             public DigestRefWrapper(long reference)
             {
    -            super(reference,"SHA512");
    +            super(reference, "SHA512");
             }
     
             @Override
    
  • core/src/main/java/org/bouncycastle/crypto/digests/SHAKENativeDigest.java+59 20 modified
    @@ -69,8 +69,11 @@ public SHAKENativeDigest(byte[] encoded)
     
         SHAKENativeDigest restoreState(byte[] state, int offset)
         {
    -        restoreFullState(nativeRef.getReference(), state, offset);
    -        return this;
    +        synchronized (this)
    +        {
    +            restoreFullState(nativeRef.getReference(), state, offset);
    +            return this;
    +        }
         }
     
         //
    @@ -87,85 +90,121 @@ public String getAlgorithmName()
         @Override
         public int getDigestSize()
         {
    -        return getDigestSize(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            return getDigestSize(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public void update(byte in)
         {
    -        update(nativeRef.getReference(), in);
    +        synchronized (this)
    +        {
    +            update(nativeRef.getReference(), in);
    +        }
         }
     
     
         @Override
         public void update(byte[] input, int inOff, int len)
         {
    -        update(nativeRef.getReference(), input, inOff, len);
    +        synchronized (this)
    +        {
    +            update(nativeRef.getReference(), input, inOff, len);
    +        }
         }
     
     
         @Override
         public int doFinal(byte[] output, int outOff)
         {
    -        int i = doFinal(nativeRef.getReference(), output, outOff);
    -        return i;
    +        synchronized (this)
    +        {
    +            int i = doFinal(nativeRef.getReference(), output, outOff);
    +            return i;
    +        }
         }
     
         @Override
         public int doFinal(byte[] out, int outOff, int outLen)
         {
    -        int i = doFinal(nativeRef.getReference(),out,outOff,outLen);
    -        return i;
    +        synchronized (this)
    +        {
    +            int i = doFinal(nativeRef.getReference(), out, outOff, outLen);
    +            return i;
    +        }
         }
     
         @Override
         public int doOutput(byte[] out, int outOff, int outLen)
         {
    -       return doOutput(nativeRef.getReference(),out,outOff,outLen);
    +        synchronized (this)
    +        {
    +            return doOutput(nativeRef.getReference(), out, outOff, outLen);
    +        }
         }
     
     
         @Override
         public void reset()
         {
    -        reset(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            reset(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public int getByteLength()
         {
    -        return getByteLength(nativeRef.getReference());
    +        synchronized (this)
    +        {
    +            return getByteLength(nativeRef.getReference());
    +        }
         }
     
     
         @Override
         public Memoable copy()
         {
    -        return new SHAKENativeDigest(this);
    +        synchronized (this)
    +        {
    +            return new SHAKENativeDigest(this);
    +        }
         }
     
         @Override
         public void reset(Memoable other)
         {
    -        SHAKENativeDigest dig = (SHAKENativeDigest) other;
    -        restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        synchronized (this)
    +        {
    +            SHAKENativeDigest dig = (SHAKENativeDigest) other;
    +            restoreFullState(nativeRef.getReference(), dig.getEncodedState(), 0);
    +        }
         }
     
     
         public byte[] getEncodedState()
         {
    -        int l = encodeFullState(nativeRef.getReference(), null, 0);
    -        byte[] state = new byte[l];
    -        encodeFullState(nativeRef.getReference(), state, 0);
    -        return state;
    +        synchronized (this)
    +        {
    +            int l = encodeFullState(nativeRef.getReference(), null, 0);
    +            byte[] state = new byte[l];
    +            encodeFullState(nativeRef.getReference(), state, 0);
    +            return state;
    +        }
         }
     
     
         void restoreFullState(byte[] encoded, int offset)
         {
    -        restoreFullState(nativeRef.getReference(), encoded, offset);
    +        synchronized (this)
    +        {
    +            restoreFullState(nativeRef.getReference(), encoded, offset);
    +        }
         }
     
     
    
  • core/src/main/java/org/bouncycastle/crypto/engines/AESNativeCBC.java+101 85 modified
    @@ -25,107 +25,113 @@ class AESNativeCBC
         public void init(boolean forEncryption, CipherParameters params)
             throws IllegalArgumentException
         {
    -        boolean oldEncrypting = this.encrypting;
     
    -        this.encrypting = forEncryption;
    -
    -        if (params instanceof ParametersWithIV)
    +        synchronized (this)
             {
    -            ParametersWithIV ivParam = (ParametersWithIV)params;
    -            byte[] iv = ivParam.getIV();
    -
    -            if (iv.length != getBlockSize())
    -            {
    -                throw new IllegalArgumentException("initialisation vector must be the same length as block size");
    -            }
    -
    -            System.arraycopy(iv, 0, IV, 0, iv.length);
    +            boolean oldEncrypting = this.encrypting;
     
    -            reset();
    +            this.encrypting = forEncryption;
     
    -            // if null it's an IV changed only.
    -            if (ivParam.getParameters() != null)
    -            {
    -                init((KeyParameter)ivParam.getParameters());
    -                // cipher.init(encrypting, ivParam.getParameters());
    -            }
    -            else
    +            if (params instanceof ParametersWithIV)
                 {
    -                // The key parameter was null which inidicates that they
    -                // IV is being changed.
    +                ParametersWithIV ivParam = (ParametersWithIV) params;
    +                byte[] iv = ivParam.getIV();
     
    -                if (oldEncrypting != encrypting)
    +                if (iv.length != getBlockSize())
                     {
    -                    throw new IllegalArgumentException("cannot change encrypting state without providing key");
    +                    throw new IllegalArgumentException("initialisation vector must be the same length as block size");
                     }
     
    -                if (referenceWrapper == null)
    +                System.arraycopy(iv, 0, IV, 0, iv.length);
    +
    +                reset();
    +
    +                // if null it's an IV changed only.
    +                if (ivParam.getParameters() != null)
                     {
    -                    throw new IllegalStateException("IV change attempted but not previously initialized with a key");
    +                    init((KeyParameter) ivParam.getParameters());
    +                    // cipher.init(encrypting, ivParam.getParameters());
                     }
    +                else
    +                {
    +                    // The key parameter was null which inidicates that they
    +                    // IV is being changed.
     
    -                // We need to use the old key because
    -                // the native layer requires a both key and iv each time.
    -                init(new KeyParameter(referenceWrapper.oldKey));
    +                    if (oldEncrypting != encrypting)
    +                    {
    +                        throw new IllegalArgumentException("cannot change encrypting state without providing key");
    +                    }
     
    -            }
    -        }
    -        else
    -        {
    -            reset();
    +                    if (referenceWrapper == null)
    +                    {
    +                        throw new IllegalStateException("IV change attempted but not previously initialized with a key");
    +                    }
     
    -            // if it's null, key is to be reused.
    -            if (params != null)
    -            {
    -                init((KeyParameter)params);
    -                // cipher.init(encrypting, params);
    +                    // We need to use the old key because
    +                    // the native layer requires a both key and iv each time.
    +                    init(new KeyParameter(referenceWrapper.oldKey));
    +
    +                }
                 }
                 else
                 {
    -                if (oldEncrypting != encrypting)
    -                {
    -                    throw new IllegalArgumentException("cannot change encrypting state without providing key.");
    -                }
    +                reset();
     
    -                if (referenceWrapper == null)
    +                // if it's null, key is to be reused.
    +                if (params != null)
                     {
    -                    throw new IllegalStateException("IV change attempted but not previously initialized with a key");
    +                    init((KeyParameter) params);
    +                    // cipher.init(encrypting, params);
                     }
    +                else
    +                {
    +                    if (oldEncrypting != encrypting)
    +                    {
    +                        throw new IllegalArgumentException("cannot change encrypting state without providing key.");
    +                    }
    +
    +                    if (referenceWrapper == null)
    +                    {
    +                        throw new IllegalStateException("IV change attempted but not previously initialized with a key");
    +                    }
     
    -                // We need to use the old key because the
    -                // native layer requires a both key and iv each time.
    -                init(new KeyParameter(referenceWrapper.oldKey));
    +                    // We need to use the old key because the
    +                    // native layer requires a both key and iv each time.
    +                    init(new KeyParameter(referenceWrapper.oldKey));
     
    +                }
                 }
             }
    -
         }
     
         private void init(KeyParameter parameters)
         {
     
    -        byte[] key = ((KeyParameter)parameters).getKey();
    +        synchronized (this)
    +        {
    +            byte[] key = ((KeyParameter) parameters).getKey();
    +
     
    +            switch (key.length)
    +            {
    +                case 16:
    +                case 24:
    +                case 32:
    +                    break;
    +                default:
    +                    throw new IllegalArgumentException("key must be only 16,24,or 32 bytes long.");
    +            }
     
    -        switch (key.length)
    -        {
    -        case 16:
    -        case 24:
    -        case 32:
    -            break;
    -        default:
    -            throw new IllegalArgumentException("key must be only 16,24,or 32 bytes long.");
    -        }
    +            referenceWrapper = new CBCRefWrapper(makeNative(key.length, encrypting), Arrays.clone(key));
     
    -        referenceWrapper = new CBCRefWrapper(makeNative(key.length, encrypting), Arrays.clone(key));
    +            if (referenceWrapper.getReference() == 0)
    +            {
    +                throw new IllegalStateException("Native CBC native instance returned a null pointer.");
    +            }
     
    -        if (referenceWrapper.getReference() == 0)
    -        {
    -            throw new IllegalStateException("Native CBC native instance returned a null pointer.");
    +            init(referenceWrapper.getReference(), key, IV);
    +            keySize = key.length * 8;
             }
    -        
    -        init(referenceWrapper.getReference(), key, IV);
    -        keySize = key.length * 8;
         }
     
     
    @@ -147,25 +153,30 @@ public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
             throws DataLengthException, IllegalStateException
         {
     
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("not initialized");
    -        }
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
     
    -        return process(referenceWrapper.getReference(), in, inOff, 1, out, outOff);
    +            return process(referenceWrapper.getReference(), in, inOff, 1, out, outOff);
    +        }
         }
     
         @Override
         public void reset()
         {
    -        // skip over spurious resets that may occur before init is called.
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            return;
    -        }
    -
    -        reset(referenceWrapper.getReference());
    +            // skip over spurious resets that may occur before init is called.
    +            if (referenceWrapper == null)
    +            {
    +                return;
    +            }
     
    +            reset(referenceWrapper.getReference());
    +        }
         }
     
     
    @@ -179,14 +190,16 @@ public int getMultiBlockSize()
         public int processBlocks(byte[] in, int inOff, int blockCount, byte[] out, int outOff)
             throws DataLengthException, IllegalStateException
         {
    +        synchronized (this)
    +        {
     
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
     
    -        if (referenceWrapper == null)
    -        {
    -            throw new IllegalStateException("not initialized");
    +            return process(referenceWrapper.getReference(), in, inOff, blockCount, out, outOff);
             }
    -
    -        return process(referenceWrapper.getReference(), in, inOff, blockCount, out, outOff);
         }
     
         private static native int process(long ref, byte[] in, int inOff, int blockCount, byte[] out, int outOff);
    @@ -206,9 +219,12 @@ public int processBlocks(byte[] in, int inOff, int blockCount, byte[] out, int o
         @Override
         public BlockCipher getUnderlyingCipher()
         {
    -        MultiBlockCipher eng = AESEngine.newInstance();
    -        eng.init(encrypting, new KeyParameter(referenceWrapper.oldKey));
    -        return eng;
    +        synchronized (this)
    +        {
    +            MultiBlockCipher eng = AESEngine.newInstance();
    +            eng.init(encrypting, new KeyParameter(referenceWrapper.oldKey));
    +            return eng;
    +        }
         }
     
     
    
  • core/src/main/java/org/bouncycastle/crypto/engines/AESNativeCCM.java+129 104 modified
    @@ -27,75 +27,81 @@ class AESNativeCCM
         @Override
         public BlockCipher getUnderlyingCipher()
         {
    -        BlockCipher engine = AESEngine.newInstance();
    -
    -        if (refWrapper != null && refWrapper.key != null)
    +        synchronized (this)
             {
    -            engine.init(true, new KeyParameter(refWrapper.key));
    -        }
    +            BlockCipher engine = AESEngine.newInstance();
     
    -        return engine;
    +            if (refWrapper != null && refWrapper.key != null)
    +            {
    +                engine.init(true, new KeyParameter(refWrapper.key));
    +            }
    +
    +            return engine;
    +        }
         }
     
     
         public void init(boolean forEncryption, CipherParameters params)
                 throws IllegalArgumentException
         {
    -        this.forEncryption = forEncryption;
    -        CipherParameters cipherParameters;
    -        KeyParameter keyParam = null;
    -
    -        byte[] nonce;
    -        byte[] initialAssociatedText;
    -        int macSize;
    -        if (params instanceof AEADParameters)
    +        synchronized (this)
             {
    -            AEADParameters param = (AEADParameters) params;
    +            this.forEncryption = forEncryption;
    +            CipherParameters cipherParameters;
    +            KeyParameter keyParam = null;
    +
    +            byte[] nonce;
    +            byte[] initialAssociatedText;
    +            int macSize;
    +            if (params instanceof AEADParameters)
    +            {
    +                AEADParameters param = (AEADParameters) params;
     
    -            nonce = param.getNonce();
    -            initialAssociatedText = param.getAssociatedText();
    -            macSize = getMacSize(forEncryption, param.getMacSize());
    -            cipherParameters = param.getKey();
    -        }
    -        else if (params instanceof ParametersWithIV)
    -        {
    -            ParametersWithIV param = (ParametersWithIV) params;
    +                nonce = param.getNonce();
    +                initialAssociatedText = param.getAssociatedText();
    +                macSize = getMacSize(forEncryption, param.getMacSize());
    +                cipherParameters = param.getKey();
    +            }
    +            else if (params instanceof ParametersWithIV)
    +            {
    +                ParametersWithIV param = (ParametersWithIV) params;
     
    -            nonce = param.getIV();
    -            initialAssociatedText = null;
    -            macSize = getMacSize(forEncryption, 64);
    -            cipherParameters = param.getParameters();
    -        }
    -        else
    -        {
    -            throw new IllegalArgumentException("invalid parameters passed to CCM");
    -        }
    +                nonce = param.getIV();
    +                initialAssociatedText = null;
    +                macSize = getMacSize(forEncryption, 64);
    +                cipherParameters = param.getParameters();
    +            }
    +            else
    +            {
    +                throw new IllegalArgumentException("invalid parameters passed to CCM");
    +            }
     
    -        // NOTE: Very basic support for key re-use, but no performance gain from it
    -        if (cipherParameters != null)
    -        {
    -            keyParam = (KeyParameter) cipherParameters;
    -        }
    +            // NOTE: Very basic support for key re-use, but no performance gain from it
    +            if (cipherParameters != null)
    +            {
    +                keyParam = (KeyParameter) cipherParameters;
    +            }
     
    -        if (keyParam != null)
    -        {
    -            byte[] key = keyParam.getKey();
    -            if (key == null)
    +            if (keyParam != null)
                 {
    -                throw new IllegalArgumentException("key was null");
    +                byte[] key = keyParam.getKey();
    +                if (key == null)
    +                {
    +                    throw new IllegalArgumentException("key was null");
    +                }
    +                initRef(key);
                 }
    -            initRef(key);
    -        }
     
    -        assert refWrapper != null;
    +            assert refWrapper != null;
     
    -        int iatLen = initialAssociatedText != null ? initialAssociatedText.length : 0;
    -        initNative(
    -                refWrapper.getReference(),
    -                forEncryption, refWrapper.getKey(),
    -                nonce, initialAssociatedText, iatLen, macSize * 8);
    -        reset();
    -        initialised = true;
    +            int iatLen = initialAssociatedText != null ? initialAssociatedText.length : 0;
    +            initNative(
    +                    refWrapper.getReference(),
    +                    forEncryption, refWrapper.key,
    +                    nonce, initialAssociatedText, iatLen, macSize * 8);
    +            reset();
    +            initialised = true;
    +        }
         }
     
     
    @@ -187,43 +193,49 @@ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
         public int doFinal(byte[] out, int outOff)
                 throws IllegalStateException, InvalidCipherTextException
         {
    -        int len;
    -        try
    +        synchronized (this)
             {
    -            checkStatus();
    -            if (out == null)
    +            int len;
    +            try
                 {
    -                throw new NullPointerException("output was null");
    +                checkStatus();
    +                if (out == null)
    +                {
    +                    throw new NullPointerException("output was null");
    +                }
    +                if (outOff < 0)
    +                {
    +                    throw new IllegalArgumentException("offset is negative");
    +                }
    +
    +                if (getOutputSize(0) > out.length - outOff)
    +                {
    +                    throw new OutputLengthException("output buffer too short");
    +                }
    +                len = processPacket(refWrapper.getReference(), data.getBuffer(), 0, data.size(), associatedText.getBuffer(), 0, associatedText.size(), out, outOff);
    +                resetKeepMac();
    +                //
    +                // BlockCipherTest, testing ShortTagException.
    +                //
                 }
    -            if (outOff < 0)
    +            catch (IllegalStateException e)
                 {
    -                throw new IllegalArgumentException("offset is negative");
    +                reset();
    +                throw e;
                 }
     
    -            if (getOutputSize(0) > out.length - outOff)
    -            {
    -                throw new OutputLengthException("output buffer too short");
    -            }
    -            len = processPacket(refWrapper.getReference(), data.getBuffer(), 0, data.size(), associatedText.getBuffer(), 0, associatedText.size(), out, outOff);
    -            resetKeepMac();
    -            //
    -            // BlockCipherTest, testing ShortTagException.
    -            //
    +            return len;
             }
    -        catch (IllegalStateException e)
    -        {
    -            reset();
    -            throw e;
    -        }
    -
    -        return len;
         }
     
     
         @Override
         public byte[] getMac()
         {
    -        return getMac(refWrapper.getReference());
    +        synchronized (this)
    +        {
    +            return getMac(refWrapper.getReference());
    +        }
         }
     
     
    @@ -237,33 +249,42 @@ public int getUpdateOutputSize(int len)
         @Override
         public int getOutputSize(int len)
         {
    -        return getOutputSize(refWrapper.getReference(), len + data.size());
    +        synchronized (this)
    +        {
    +            return getOutputSize(refWrapper.getReference(), len + data.size());
    +        }
         }
     
     
         @Override
         public void reset()
         {
    -        if (refWrapper == null)
    +        synchronized (this)
             {
    -            // deal with reset being called before init.
    -            return;
    +            if (refWrapper == null)
    +            {
    +                // deal with reset being called before init.
    +                return;
    +            }
    +            associatedText.reset();
    +            data.reset();
    +            reset(refWrapper.getReference(), false);
             }
    -        associatedText.reset();
    -        data.reset();
    -        reset(refWrapper.getReference(), false);
         }
     
         private void resetKeepMac()
         {
    -        if (refWrapper == null)
    +        synchronized (this)
             {
    -            // deal with reset being called before init.
    -            return;
    +            if (refWrapper == null)
    +            {
    +                // deal with reset being called before init.
    +                return;
    +            }
    +            associatedText.reset();
    +            data.reset();
    +            reset(refWrapper.getReference(), true);
             }
    -        associatedText.reset();
    -        data.reset();
    -        reset(refWrapper.getReference(), true);
         }
     
     
    @@ -306,19 +327,25 @@ static native int processPacket(long ref, byte[] in, int inOff, int inLen, byte[
         public int processPacket(byte[] inBuf, int inOff, int length, byte[] outBuf, int outOff)
                 throws InvalidCipherTextException
         {
    -        int result = processPacket(refWrapper.getReference(), inBuf, inOff, length, associatedText.getBuffer(), 0, associatedText.size(), outBuf, outOff);
    -        reset();
    -        return result;
    +        synchronized (this)
    +        {
    +            int result = processPacket(refWrapper.getReference(), inBuf, inOff, length, associatedText.getBuffer(), 0, associatedText.size(), outBuf, outOff);
    +            reset();
    +            return result;
    +        }
         }
     
         @Override
         public byte[] processPacket(byte[] input, int inOff, int length)
                 throws InvalidCipherTextException
         {
    -        byte[] out = new byte[getOutputSize(length)];
    -        processPacket(input, inOff, length, out, 0);
    -        reset();
    -        return out;
    +        synchronized (this)
    +        {
    +            byte[] out = new byte[getOutputSize(length)];
    +            processPacket(input, inOff, length, out, 0);
    +            reset();
    +            return out;
    +        }
         }
     
         private static class CCMRefWrapper
    @@ -339,11 +366,6 @@ public Runnable createAction()
                 return new Disposer(reference, key);
             }
     
    -
    -        public byte[] getKey()
    -        {
    -            return key;
    -        }
         }
     
     
    @@ -373,11 +395,14 @@ protected void dispose(long reference)
         @Override
         public String toString()
         {
    -        if (refWrapper != null && refWrapper.key != null)
    +        synchronized (this)
             {
    -            return "CCM[Native](AES[Native](" + (refWrapper.key.length * 8) + "))";
    +            if (refWrapper != null && refWrapper.key != null)
    +            {
    +                return "CCM[Native](AES[Native](" + (refWrapper.key.length * 8) + "))";
    +            }
    +            return "CCM[Native](AES[Native](not initialized))";
             }
    -        return "CCM[Native](AES[Native](not initialized))";
         }
     
     
    
  • core/src/main/java/org/bouncycastle/crypto/engines/AESNativeCFB.java+93 76 modified
    @@ -39,77 +39,78 @@ public AESNativeCFB(int bitSize)
         public void init(boolean forEncryption, CipherParameters params)
                 throws IllegalArgumentException
         {
    +        synchronized (this)
    +        {
    +            boolean oldEncrypting = this.encrypting;
     
    -        boolean oldEncrypting = this.encrypting;
    -
    -        this.encrypting = forEncryption;
    -
    -        byte[] key = null;
    -        byte[] iv = null;
    +            this.encrypting = forEncryption;
     
    -        if (params instanceof ParametersWithIV)
    -        {
    -            ParametersWithIV ivParam = (ParametersWithIV) params;
    -            iv = ivParam.getIV();
    +            byte[] key = null;
    +            byte[] iv = null;
     
    -            if (iv.length > getBlockSize() || iv.length < 1)
    +            if (params instanceof ParametersWithIV)
                 {
    -                throw new IllegalArgumentException("initialisation vector must be between one and block size length");
    +                ParametersWithIV ivParam = (ParametersWithIV) params;
    +                iv = ivParam.getIV();
    +
    +                if (iv.length > getBlockSize() || iv.length < 1)
    +                {
    +                    throw new IllegalArgumentException("initialisation vector must be between one and block size length");
    +                }
    +
    +                if (iv.length < getBlockSize())
    +                {
    +                    byte[] newIv = new byte[getBlockSize()];
    +                    System.arraycopy(iv, 0, newIv, newIv.length - iv.length, iv.length);
    +                    iv = newIv;
    +                }
    +
    +                oldIv = Arrays.clone(iv);
    +
    +                if (ivParam.getParameters() != null)
    +                {
    +                    key = Arrays.clone(((KeyParameter) ivParam.getParameters()).getKey());
    +                }
    +
    +                if (key != null)
    +                {
    +                    oldEncrypting = encrypting; // Can change because key is supplied.
    +                    key = Arrays.clone(key);
    +                }
    +                else
    +                {
    +                    // Use old key, it may be null but that is tested later.
    +                    key = referenceWrapper != null ? referenceWrapper.getKey() : null;
    +                }
                 }
    -
    -            if (iv.length < getBlockSize())
    +            else
                 {
    -                byte[] newIv = new byte[getBlockSize()];
    -                System.arraycopy(iv, 0, newIv, newIv.length - iv.length, iv.length);
    -                iv = newIv;
    -            }
    +                //
    +                // Change of key.
    +                //
     
    -            oldIv = Arrays.clone(iv);
    +                if (params instanceof KeyParameter)
    +                {
    +                    key = Arrays.clone(((KeyParameter) params).getKey());
    +                    iv = oldIv;
    +                }
     
    -            if (ivParam.getParameters() != null)
    -            {
    -                key = Arrays.clone(((KeyParameter) ivParam.getParameters()).getKey());
                 }
     
    -            if (key != null)
    -            {
    -                oldEncrypting = encrypting; // Can change because key is supplied.
    -                key = Arrays.clone(key);
    -            }
    -            else
    +            if (key == null && oldEncrypting != encrypting)
                 {
    -                // Use old key, it may be null but that is tested later.
    -                key =  referenceWrapper!=null? referenceWrapper.getKey():null;
    +                throw new IllegalArgumentException("cannot change encrypting state without providing key.");
                 }
    -        }
    -        else
    -        {
    -            //
    -            // Change of key.
    -            //
     
    -            if (params instanceof KeyParameter)
    +            if (iv == null)
                 {
    -                key = Arrays.clone(((KeyParameter) params).getKey());
    -                iv = oldIv;
    +                throw new IllegalArgumentException("iv is null");
                 }
     
    -        }
     
    -        if (key == null && oldEncrypting != encrypting)
    -        {
    -            throw new IllegalArgumentException("cannot change encrypting state without providing key.");
    +            referenceWrapper = new CFBRefWrapper(makeNative(encrypting, key.length), key);
    +            init(referenceWrapper.getReference(), key, iv);
             }
    -
    -        if (iv == null)
    -        {
    -            throw new IllegalArgumentException("iv is null");
    -        }
    -
    -
    -        referenceWrapper = new CFBRefWrapper(makeNative(encrypting, key.length), key);
    -        init(referenceWrapper.getReference(), key, iv);
    -
         }
     
     
    @@ -122,21 +123,27 @@ public String getAlgorithmName()
         @Override
         public byte returnByte(byte in)
         {
    -        return processByte(referenceWrapper.getReference(), in);
    +        synchronized (this)
    +        {
    +            return processByte(referenceWrapper.getReference(), in);
    +        }
         }
     
         @Override
         public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
                 throws DataLengthException
         {
     
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("not initialized");
    -        }
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
     
     
    -        return processBytes(referenceWrapper.getReference(), in, inOff, len, out, outOff);
    +            return processBytes(referenceWrapper.getReference(), in, inOff, len, out, outOff);
    +        }
         }
     
         @Override
    @@ -150,25 +157,30 @@ public int getBlockSize()
         public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
                 throws DataLengthException, IllegalStateException
         {
    -
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("not initialized");
    -        }
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
     
    -        return processBytes(referenceWrapper.getReference(), in, inOff, getBlockSize(), out, outOff);
    +            return processBytes(referenceWrapper.getReference(), in, inOff, getBlockSize(), out, outOff);
    +        }
         }
     
         @Override
         public void reset()
         {
    -        // skip over spurious resets that may occur before init is called.
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            return;
    -        }
    +            // skip over spurious resets that may occur before init is called.
    +            if (referenceWrapper == null)
    +            {
    +                return;
    +            }
     
    -        reset(referenceWrapper.getReference());
    +            reset(referenceWrapper.getReference());
    +        }
     
         }
     
    @@ -184,13 +196,15 @@ public int processBlocks(byte[] in, int inOff, int blockCount, byte[] out, int o
                 throws DataLengthException, IllegalStateException
         {
     
    -
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("CFB engine not initialized");
    -        }
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("CFB engine not initialized");
    +            }
     
    -        return processBytes(in, inOff, blockCount * getBlockSize(), out, outOff);
    +            return processBytes(in, inOff, blockCount * getBlockSize(), out, outOff);
    +        }
         }
     
     
    @@ -255,11 +269,14 @@ public Runnable createAction()
     
         public String toString()
         {
    -        if (referenceWrapper != null && referenceWrapper.getKey() != null)
    +        synchronized (this)
             {
    -            return "CFB[Native](AES[Native](" + (referenceWrapper.getKey().length * 8) + "))";
    +            if (referenceWrapper != null && referenceWrapper.getKey() != null)
    +            {
    +                return "CFB[Native](AES[Native](" + (referenceWrapper.getKey().length * 8) + "))";
    +            }
    +            return "CFB[Native](AES[Native](not initialized))";
             }
    -        return "CFB[Native](AES[Native](not initialized))";
         }
     
     }
    
  • core/src/main/java/org/bouncycastle/crypto/engines/AESNativeCTR.java+110 78 modified
    @@ -1,6 +1,8 @@
     package org.bouncycastle.crypto.engines;
     
    -import org.bouncycastle.crypto.*;
    +import org.bouncycastle.crypto.BlockCipher;
    +import org.bouncycastle.crypto.CipherParameters;
    +import org.bouncycastle.crypto.DataLengthException;
     import org.bouncycastle.crypto.modes.CTRModeCipher;
     import org.bouncycastle.crypto.params.KeyParameter;
     import org.bouncycastle.crypto.params.ParametersWithIV;
    @@ -23,16 +25,19 @@ public AESNativeCTR()
     
         public BlockCipher getUnderlyingCipher()
         {
    -        BlockCipher engine = AESEngine.newInstance();
    -        if (referenceWrapper != null)
    +        synchronized (this)
             {
    -            byte[] k = referenceWrapper.getKey();
    -            if (k != null)
    +            BlockCipher engine = AESEngine.newInstance();
    +            if (referenceWrapper != null)
                 {
    -                engine.init(true, new KeyParameter(referenceWrapper.getKey()));
    +                byte[] k = referenceWrapper.getKey();
    +                if (k != null)
    +                {
    +                    engine.init(true, new KeyParameter(referenceWrapper.getKey()));
    +                }
                 }
    +            return engine;
             }
    -        return engine;
         }
     
     
    @@ -47,124 +52,143 @@ public int getBlockSize()
         public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
                 throws DataLengthException, IllegalStateException
         {
    -
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("not initialized");
    -        }
    -
    -        return processBytes(referenceWrapper.getReference(), in, inOff, getBlockSize(), out, outOff);
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
     
    +            return processBytes(referenceWrapper.getReference(), in, inOff, getBlockSize(), out, outOff);
    +        }
         }
     
         @Override
         public int getMultiBlockSize()
         {
    -        return getMultiBlockSize(0);
    +        synchronized (this)
    +        {
    +            return getMultiBlockSize(0);
    +        }
         }
     
         @Override
         public int processBlocks(byte[] in, int inOff, int blockCount, byte[] out, int outOff)
                 throws DataLengthException, IllegalStateException
         {
     
    -        int extent = getBlockSize() * blockCount;
    -
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("not initialized");
    -        }
    +            int extent = getBlockSize() * blockCount;
    +
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
     
    -        return processBytes(referenceWrapper.getReference(), in, inOff, extent, out, outOff);
    +            return processBytes(referenceWrapper.getReference(), in, inOff, extent, out, outOff);
    +        }
     
         }
     
         @Override
         public long skip(long numberOfBytes)
         {
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("not initialized");
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +            return skip(referenceWrapper.getReference(), numberOfBytes);
             }
    -        return skip(referenceWrapper.getReference(), numberOfBytes);
         }
     
         @Override
         public long seekTo(long position)
         {
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("not initialized");
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +            return seekTo(referenceWrapper.getReference(), position);
             }
    -        return seekTo(referenceWrapper.getReference(), position);
         }
     
         @Override
         public long getPosition()
         {
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("not initialized");
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +            return getPosition(referenceWrapper.getReference());
             }
    -        return getPosition(referenceWrapper.getReference());
         }
     
     
         @Override
         public void init(boolean forEncryption, CipherParameters params)
                 throws IllegalArgumentException
         {
    -        if (params instanceof ParametersWithIV)
    +        synchronized (this)
             {
    -            ParametersWithIV ivParam = (ParametersWithIV) params;
    -            byte[] iv = ivParam.getIV();
    -
    -            int blockSize = getBlockSize();
    +            if (params instanceof ParametersWithIV)
    +            {
    +                ParametersWithIV ivParam = (ParametersWithIV) params;
    +                byte[] iv = ivParam.getIV();
     
    -            int maxCounterSize = (8 > blockSize / 2) ? blockSize / 2 : 8;
    +                int blockSize = getBlockSize();
     
    -            if (blockSize - iv.length > maxCounterSize)
    -            {
    -                throw new IllegalArgumentException("CTR mode requires IV of at least: " + (blockSize - maxCounterSize) + " bytes.");
    -            }
    +                int maxCounterSize = (8 > blockSize / 2) ? blockSize / 2 : 8;
     
    -            //
    -            // if null it's an IV changed only.
    -            if (ivParam.getParameters() == null)
    -            {
    -                if (referenceWrapper == null)
    +                if (blockSize - iv.length > maxCounterSize)
                     {
    -                    referenceWrapper = new CTRRefWrapper(makeCTRInstance(), null);
    +                    throw new IllegalArgumentException("CTR mode requires IV of at least: " + (blockSize - maxCounterSize) + " bytes.");
                     }
    -                init(referenceWrapper.getReference(), referenceWrapper.getKey(), iv);
    -            }
    -            else
    -            {
    -                byte[] key = ((KeyParameter) ivParam.getParameters()).getKey();
     
    -                switch (key.length)
    +                //
    +                // if null it's an IV changed only.
    +                if (ivParam.getParameters() == null)
                     {
    -                    case 16:
    -                    case 24:
    -                    case 32:
    -                        break;
    -                    default:
    -                        throw new IllegalArgumentException("invalid key length, key must be 16,24 or 32 bytes");
    +                    if (referenceWrapper == null)
    +                    {
    +                        referenceWrapper = new CTRRefWrapper(makeCTRInstance(), null);
    +                    }
    +                    init(referenceWrapper.getReference(), referenceWrapper.getKey(), iv);
                     }
    +                else
    +                {
    +                    byte[] key = ((KeyParameter) ivParam.getParameters()).getKey();
     
    +                    switch (key.length)
    +                    {
    +                        case 16:
    +                        case 24:
    +                        case 32:
    +                            break;
    +                        default:
    +                            throw new IllegalArgumentException("invalid key length, key must be 16,24 or 32 bytes");
    +                    }
     
    -                keyLen = key.length * 8;
     
    -                referenceWrapper = new CTRRefWrapper(makeCTRInstance(), key);
    -                init(referenceWrapper.getReference(), referenceWrapper.getKey(), iv);
    +                    keyLen = key.length * 8;
     
    -            }
    +                    referenceWrapper = new CTRRefWrapper(makeCTRInstance(), key);
    +                    init(referenceWrapper.getReference(), referenceWrapper.getKey(), iv);
     
    -            reset();
    -        }
    -        else
    -        {
    -            throw new IllegalArgumentException("CTR mode requires ParametersWithIV");
    +                }
    +
    +                reset();
    +            }
    +            else
    +            {
    +                throw new IllegalArgumentException("CTR mode requires ParametersWithIV");
    +            }
             }
         }
     
    @@ -179,36 +203,44 @@ public String getAlgorithmName()
         @Override
         public byte returnByte(byte in)
         {
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("not initialized");
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +            return returnByte(referenceWrapper.getReference(), in);
             }
    -        return returnByte(referenceWrapper.getReference(), in);
         }
     
         @Override
         public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
                 throws DataLengthException
         {
    -
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("not initialized");
    -        }
    +            if (referenceWrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
     
    -        return processBytes(referenceWrapper.getReference(), in, inOff, len, out, outOff);
    +            return processBytes(referenceWrapper.getReference(), in, inOff, len, out, outOff);
    +        }
         }
     
     
         @Override
         public void reset()
         {
    -        if (referenceWrapper == null)
    +        synchronized (this)
             {
    -            return;
    -        }
    +            if (referenceWrapper == null)
    +            {
    +                return;
    +            }
     
    -        reset(referenceWrapper.getReference());
    +            reset(referenceWrapper.getReference());
    +        }
         }
     
         private static native long getPosition(long reference);
    
  • core/src/main/java/org/bouncycastle/crypto/engines/AESNativeEngine.java+66 52 modified
    @@ -48,40 +48,43 @@ class AESNativeEngine
         public void init(boolean forEncryption, CipherParameters params)
             throws IllegalArgumentException
         {
    -        if (params instanceof KeyParameter)
    +        synchronized (this)
             {
    -            byte[] key = ((KeyParameter)params).getKey();
    -
    -            switch (key.length)
    +            if (params instanceof KeyParameter)
                 {
    -            case 16:
    -            case 24:
    -            case 32:
    -                wrapper = new ECBNativeRef(makeInstance(key.length, forEncryption));
    -                break;
    -
    -            default:
    -                throw new IllegalArgumentException("key must be 16, 24 or 32 bytes");
    -            }
    +                byte[] key = ((KeyParameter) params).getKey();
     
    -            CryptoServicesRegistrar.checkConstraints(
    -                new DefaultServiceProperties(
    -                    getAlgorithmName(),
    -                    key.length * 8,
    -                    params,
    -                    forEncryption ? CryptoServicePurpose.ENCRYPTION : CryptoServicePurpose.DECRYPTION
    -                ));
    +                switch (key.length)
    +                {
    +                    case 16:
    +                    case 24:
    +                    case 32:
    +                        wrapper = new ECBNativeRef(makeInstance(key.length, forEncryption));
    +                        break;
     
    +                    default:
    +                        throw new IllegalArgumentException("key must be 16, 24 or 32 bytes");
    +                }
     
    -            init(wrapper.getReference(), key);
    +                CryptoServicesRegistrar.checkConstraints(
    +                        new DefaultServiceProperties(
    +                                getAlgorithmName(),
    +                                key.length * 8,
    +                                params,
    +                                forEncryption ? CryptoServicePurpose.ENCRYPTION : CryptoServicePurpose.DECRYPTION
    +                        ));
     
    -            keyLen = key.length * 8;
     
    -            return;
    -        }
    +                init(wrapper.getReference(), key);
     
    +                keyLen = key.length * 8;
     
    -        throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName());
    +                return;
    +            }
    +
    +
    +            throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName());
    +        }
         }
     
         @Override
    @@ -100,12 +103,16 @@ public int getBlockSize()
         public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
             throws DataLengthException, IllegalStateException
         {
    -        if (wrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("not initialized");
    -        }
     
    -        return process(wrapper.getReference(), in, inOff, 1, out, outOff);
    +            if (wrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
    +
    +            return process(wrapper.getReference(), in, inOff, 1, out, outOff);
    +        }
         }
     
         @Override
    @@ -119,42 +126,34 @@ public int getMultiBlockSize()
         public int processBlocks(byte[] in, int inOff, int blockCount, byte[] out, int outOff)
             throws DataLengthException, IllegalStateException
         {
    -
    -
    -        if (wrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("not initialized");
    -        }
    +
    +            if (wrapper == null)
    +            {
    +                throw new IllegalStateException("not initialized");
    +            }
     
     
    -        return process(wrapper.getReference(), in, inOff, blockCount, out, outOff);
    +            return process(wrapper.getReference(), in, inOff, blockCount, out, outOff);
    +        }
         }
     
         @Override
         public void reset()
         {
    -        // skip over spurious resets that may occur before init is called.
    -        if (wrapper == null)
    +        synchronized (this)
             {
    -            return;
    +            // skip over spurious resets that may occur before init is called.
    +            if (wrapper == null)
    +            {
    +                return;
    +            }
    +            reset(wrapper.getReference());
             }
    -        reset(wrapper.getReference());
         }
     
     
    -    private static native void reset(long ref);
    -
    -    private static native int process(long ref, byte[] in, int inOff, int blocks, byte[] out, int outOff);
    -
    -    private static native int getMultiBlockSize(long nativeRef);
    -
    -    private static native int getBlockSize(long ref);
    -
    -    static native long makeInstance(int length, boolean forEncryption);
    -
    -    static native void dispose(long ref);
    -
    -    static native void init(long nativeRef, byte[] key);
     
         @Override
         public GCMModeCipher createGCM()
    @@ -273,4 +272,19 @@ public String toString()
         {
             return "AES[Native](" + keyLen + ")";
         }
    +
    +    private static native void reset(long ref);
    +
    +    private static native int process(long ref, byte[] in, int inOff, int blocks, byte[] out, int outOff);
    +
    +    private static native int getMultiBlockSize(long nativeRef);
    +
    +    private static native int getBlockSize(long ref);
    +
    +    static native long makeInstance(int length, boolean forEncryption);
    +
    +    static native void dispose(long ref);
    +
    +    static native void init(long nativeRef, byte[] key);
    +
     }
    
  • core/src/main/java/org/bouncycastle/crypto/engines/AESNativeGCM.java+205 163 modified
    @@ -25,109 +25,115 @@ class AESNativeGCM
         @Override
         public BlockCipher getUnderlyingCipher()
         {
    -        BlockCipher engine = AESEngine.newInstance();
    -        if (refWrapper != null && refWrapper.key != null)
    +        synchronized (this)
             {
    -            engine.init(true, new KeyParameter(refWrapper.key));
    +            BlockCipher engine = AESEngine.newInstance();
    +            if (refWrapper != null && refWrapper.key != null)
    +            {
    +                engine.init(true, new KeyParameter(refWrapper.key));
    +            }
    +            return engine;
             }
    -        return engine;
         }
     
     
         public void init(boolean forEncryption, CipherParameters params)
                 throws IllegalArgumentException
         {
    -        this.forEncryption = forEncryption;
    -        KeyParameter keyParam;
    -        byte[] newNonce = null;
    -        keptMac = null;
    -        int macSize;
    -        byte[] initialAssociatedText;
    -
    -        if (params instanceof AEADParameters)
    +        synchronized (this)
             {
    -            AEADParameters param = (AEADParameters) params;
    -
    -            newNonce = param.getNonce();
    -            initialAssociatedText = param.getAssociatedText();
    -
    -            int macSizeBits = param.getMacSize();
    -            if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0)
    +            this.forEncryption = forEncryption;
    +            KeyParameter keyParam;
    +            byte[] newNonce = null;
    +            keptMac = null;
    +            int macSize;
    +            byte[] initialAssociatedText;
    +
    +            if (params instanceof AEADParameters)
                 {
    -                throw new IllegalArgumentException("invalid value for MAC size: " + macSizeBits);
    -            }
    +                AEADParameters param = (AEADParameters) params;
     
    -            macSize = macSizeBits;
    -            keyParam = param.getKey();
    -        }
    -        else if (params instanceof ParametersWithIV)
    -        {
    -            ParametersWithIV param = (ParametersWithIV) params;
    +                newNonce = param.getNonce();
    +                initialAssociatedText = param.getAssociatedText();
     
    -            newNonce = param.getIV();
    -            initialAssociatedText = null;
    -            macSize = 128;
    -            keyParam = (KeyParameter) param.getParameters();
    -        }
    -        else
    -        {
    -            throw new IllegalArgumentException("invalid parameters passed to GCM");
    -        }
    +                int macSizeBits = param.getMacSize();
    +                if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0)
    +                {
    +                    throw new IllegalArgumentException("invalid value for MAC size: " + macSizeBits);
    +                }
     
    -        if (newNonce == null || newNonce.length < 12)
    -        {
    -            throw new IllegalArgumentException("IV must be at least 12 bytes");
    -        }
    +                macSize = macSizeBits;
    +                keyParam = param.getKey();
    +            }
    +            else if (params instanceof ParametersWithIV)
    +            {
    +                ParametersWithIV param = (ParametersWithIV) params;
     
    -        byte[] key = null;
    +                newNonce = param.getIV();
    +                initialAssociatedText = null;
    +                macSize = 128;
    +                keyParam = (KeyParameter) param.getParameters();
    +            }
    +            else
    +            {
    +                throw new IllegalArgumentException("invalid parameters passed to GCM");
    +            }
     
    -        if (forEncryption)
    -        {
    -            if (oldNonce != null && Arrays.areEqual(oldNonce, newNonce))
    +            if (newNonce == null || newNonce.length < 12)
                 {
    -                if (keyParam == null)
    -                {
    -                    throw new IllegalArgumentException("cannot reuse nonce for GCM encryption");
    -                }
    +                throw new IllegalArgumentException("IV must be at least 12 bytes");
    +            }
     
    -                if (refWrapper != null && refWrapper.key != null && Arrays.areEqual(refWrapper.key, keyParam.getKey()))
    -                {
    -                    // same nonce, same key
    -                    throw new IllegalArgumentException("cannot reuse nonce for GCM encryption");
    -                }
    +            byte[] key = null;
     
    -                if (refWrapper != null && refWrapper.key != null)
    +            if (forEncryption)
    +            {
    +                if (oldNonce != null && Arrays.areEqual(oldNonce, newNonce))
                     {
    -                    key = Arrays.clone(refWrapper.key); // Case keyParam is null
    +                    if (keyParam == null)
    +                    {
    +                        throw new IllegalArgumentException("cannot reuse nonce for GCM encryption");
    +                    }
    +
    +                    if (refWrapper != null && refWrapper.key != null && Arrays.areEqual(refWrapper.key, keyParam.getKey()))
    +                    {
    +                        // same nonce, same key
    +                        throw new IllegalArgumentException("cannot reuse nonce for GCM encryption");
    +                    }
    +
    +                    if (refWrapper != null && refWrapper.key != null)
    +                    {
    +                        key = Arrays.clone(refWrapper.key); // Case keyParam is null
    +                    }
                     }
                 }
    -        }
     
    -        oldNonce = newNonce;
    +            oldNonce = newNonce;
     
    -        if (keyParam != null)
    -        {
    -            key = keyParam.getKey();
    -            switch (key.length)
    +            if (keyParam != null)
                 {
    -                case 16:
    -                case 24:
    -                case 32:
    -                    break;
    -                default:
    -                    throw new IllegalStateException("key must be only 16,24,or 32 bytes long.");
    +                key = keyParam.getKey();
    +                switch (key.length)
    +                {
    +                    case 16:
    +                    case 24:
    +                    case 32:
    +                        break;
    +                    default:
    +                        throw new IllegalStateException("key must be only 16,24,or 32 bytes long.");
    +                }
                 }
    -        }
     
    -        initRef(key);
    +            initRef(key);
     
    -        initNative(
    -                refWrapper.getReference(),
    -                forEncryption, key,
    -                oldNonce, initialAssociatedText, macSize);
    +            initNative(
    +                    refWrapper.getReference(),
    +                    forEncryption, key,
    +                    oldNonce, initialAssociatedText, macSize);
     
     
    -        initialised = true;
    +            initialised = true;
    +        }
         }
     
     
    @@ -146,50 +152,59 @@ public String getAlgorithmName()
         @Override
         public void processAADByte(byte in)
         {
    -        processAADByte(refWrapper.getReference(), in);
    +        synchronized (this)
    +        {
    +            processAADByte(refWrapper.getReference(), in);
    +        }
         }
     
     
         @Override
         public void processAADBytes(byte[] in, int inOff, int len)
         {
    -
    -//
    -        if (refWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("GCM is uninitialized");
    -        }
    +//
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException("GCM is uninitialized");
    +            }
     
    -        processAADBytes(refWrapper.getReference(), in, inOff, len);
    +            processAADBytes(refWrapper.getReference(), in, inOff, len);
    +        }
         }
     
     
         @Override
         public int processByte(byte in, byte[] out, int outOff)
                 throws DataLengthException
         {
    +        synchronized (this)
    +        {
     
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException("GCM is uninitialized");
    +            }
     
    -        if (refWrapper == null)
    -        {
    -            throw new IllegalStateException("GCM is uninitialized");
    +            return processByte(refWrapper.getReference(), in, out, outOff);
             }
    -
    -        return processByte(refWrapper.getReference(), in, out, outOff);
         }
     
     
         @Override
         public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
                 throws DataLengthException
         {
    -
    -        if (refWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException("GCM is uninitialized");
    -        }
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException("GCM is uninitialized");
    +            }
     
    -        return processBytes(refWrapper.getReference(), in, inOff, len, out, outOff);
    +            return processBytes(refWrapper.getReference(), in, inOff, len, out, outOff);
    +        }
         }
     
     
    @@ -198,70 +213,88 @@ public int doFinal(byte[] out, int outOff)
                 throws IllegalStateException, InvalidCipherTextException
         {
     
    -        checkStatus();
    +        synchronized (this)
    +        {
    +            checkStatus();
     
     
    -        int len = doFinal(refWrapper.getReference(), out, outOff);
    +            int len = doFinal(refWrapper.getReference(), out, outOff);
     
    -        //
    -        // BlockCipherTest, testing ShortTagException.
    -        //
    +            //
    +            // BlockCipherTest, testing ShortTagException.
    +            //
     
    -        resetKeepMac();
    -        return len;
    +            resetKeepMac();
    +            return len;
    +        }
         }
     
     
         @Override
         public byte[] getMac()
         {
    -        if (keptMac != null)
    +        synchronized (this)
             {
    -            return Arrays.clone(keptMac);
    +            if (keptMac != null)
    +            {
    +                return Arrays.clone(keptMac);
    +            }
    +            return getMac(refWrapper.getReference());
             }
    -        return getMac(refWrapper.getReference());
         }
     
     
         @Override
         public int getUpdateOutputSize(int len)
         {
    -        return getUpdateOutputSize(refWrapper.getReference(), len);
    +        synchronized (this)
    +        {
    +            return getUpdateOutputSize(refWrapper.getReference(), len);
    +        }
         }
     
     
         @Override
         public int getOutputSize(int len)
         {
    -        return getOutputSize(refWrapper.getReference(), len);
    +        synchronized (this)
    +        {
    +            return getOutputSize(refWrapper.getReference(), len);
    +        }
         }
     
     
         @Override
         public void reset()
         {
    -        if (refWrapper == null)
    +        synchronized (this)
             {
    -            // deal with reset being called before init.
    -            return;
    -        }
    +            if (refWrapper == null)
    +            {
    +                // deal with reset being called before init.
    +                return;
    +            }
     
    -        reset(refWrapper.getReference());
    -        initialised = false;
    +            reset(refWrapper.getReference());
    +            initialised = false;
    +        }
     
         }
     
         private void resetKeepMac()
         {
    -        if (refWrapper == null)
    +        synchronized (this)
             {
    -            // deal with reset being called before init.
    -            return;
    -        }
    +            if (refWrapper == null)
    +            {
    +                // deal with reset being called before init.
    +                return;
    +            }
     
    -        keptMac = getMac();
    -        reset(refWrapper.getReference());
    -        initialised = false;
    +            keptMac = getMac();
    +            reset(refWrapper.getReference());
    +            initialised = false;
    +        }
         }
     
     
    @@ -277,53 +310,21 @@ private void checkStatus()
             }
         }
     
    -    private native void reset(long ref);
    -
    -    static native void initNative(
    -            long reference,
    -            boolean forEncryption,
    -            byte[] keyParam,
    -            byte[] nonce,
    -            byte[] initialAssociatedText,
    -            int macSizeBits);
    -
    -    static native long makeInstance(int keySize, boolean forEncryption);
     
    -    static native void dispose(long nativeRef);
     
    -    private static native void processAADByte(long ref, byte in);
    -
    -    private static native void processAADBytes(long ref, byte[] in, int inOff, int len);
    -
    -    private static native int processByte(long ref, byte in, byte[] out, int outOff);
    -
    -    private static native int processBytes(long ref, byte[] in, int inOff, int len, byte[] out, int outOff);
    -
    -    private static native int doFinal(long ref, byte[] out, int outOff);
    -
    -    private static native int getUpdateOutputSize(long ref, int len);
    -
    -    private static native int getOutputSize(long ref, int len);
    -
    -    public static native byte[] getMac(long ref);
    -
    -    /**
    -     * Set blocks remaining but only to a lesser value and only if the transformation has processed no data.
    -     * Functionality limited to within the module only.
    -     *
    -     * @param value the step value.
    -     */
    -    void setBlocksRemainingDown(long value)
    +    @Override
    +    public String toString()
         {
    -        setBlocksRemainingDown(refWrapper.getReference(), value);
    +        synchronized (this)
    +        {
    +            if (refWrapper.key != null)
    +            {
    +                return "GCM[Native](AES[Native](" + (refWrapper.key.length * 8) + "))";
    +            }
    +            return "GCM[Native](AES[Native](not initialized))";
    +        }
         }
     
    -    // Set the blocks remaining, but only to a lesser value.
    -    // This is intended for testing only and will throw from the native side if the
    -    // transformation has processed any data.
    -    private native void setBlocksRemainingDown(long nativeRef, long value);
    -
    -
         private static class GCMRefWrapper
                 extends NativeReference
         {
    @@ -363,13 +364,54 @@ protected void dispose(long reference)
             }
         }
     
    -    @Override
    -    public String toString()
    +    private native void reset(long ref);
    +
    +    static native void initNative(
    +            long reference,
    +            boolean forEncryption,
    +            byte[] keyParam,
    +            byte[] nonce,
    +            byte[] initialAssociatedText,
    +            int macSizeBits);
    +
    +    static native long makeInstance(int keySize, boolean forEncryption);
    +
    +    static native void dispose(long nativeRef);
    +
    +    private static native void processAADByte(long ref, byte in);
    +
    +    private static native void processAADBytes(long ref, byte[] in, int inOff, int len);
    +
    +    private static native int processByte(long ref, byte in, byte[] out, int outOff);
    +
    +    private static native int processBytes(long ref, byte[] in, int inOff, int len, byte[] out, int outOff);
    +
    +    private static native int doFinal(long ref, byte[] out, int outOff);
    +
    +    private static native int getUpdateOutputSize(long ref, int len);
    +
    +    private static native int getOutputSize(long ref, int len);
    +
    +    public static native byte[] getMac(long ref);
    +
    +    /**
    +     * Set blocks remaining but only to a lesser value and only if the transformation has processed no data.
    +     * Functionality limited to within the module only.
    +     *
    +     * @param value the step value.
    +     */
    +    void setBlocksRemainingDown(long value)
         {
    -        if (refWrapper.key != null)
    +        synchronized (this)
             {
    -            return "GCM[Native](AES[Native](" + (refWrapper.key.length * 8) + "))";
    +            setBlocksRemainingDown(refWrapper.getReference(), value);
             }
    -        return "GCM[Native](AES[Native](not initialized))";
         }
    +
    +    // Set the blocks remaining, but only to a lesser value.
    +    // This is intended for testing only and will throw from the native side if the
    +    // transformation has processed any data.
    +    private native void setBlocksRemainingDown(long nativeRef, long value);
    +
    +
     }
    
  • core/src/main/java/org/bouncycastle/crypto/engines/AESNativeGCMSIV.java+125 99 modified
    @@ -1,12 +1,6 @@
     package org.bouncycastle.crypto.engines;
     
    -import java.io.ByteArrayOutputStream;
    -
    -import org.bouncycastle.crypto.BlockCipher;
    -import org.bouncycastle.crypto.CipherParameters;
    -import org.bouncycastle.crypto.DataLengthException;
    -import org.bouncycastle.crypto.ExceptionMessages;
    -import org.bouncycastle.crypto.InvalidCipherTextException;
    +import org.bouncycastle.crypto.*;
     import org.bouncycastle.crypto.modes.GCMSIVModeCipher;
     import org.bouncycastle.crypto.params.AEADParameters;
     import org.bouncycastle.crypto.params.KeyParameter;
    @@ -15,6 +9,8 @@
     import org.bouncycastle.util.dispose.NativeDisposer;
     import org.bouncycastle.util.dispose.NativeReference;
     
    +import java.io.ByteArrayOutputStream;
    +
     public class AESNativeGCMSIV
             implements GCMSIVModeCipher
     {
    @@ -46,68 +42,73 @@ public class AESNativeGCMSIV
         @Override
         public BlockCipher getUnderlyingCipher()
         {
    -        BlockCipher engine = AESEngine.newInstance();
    -        if (lastKey != null)
    +        synchronized (this)
             {
    -            engine.init(true, new KeyParameter(lastKey));
    +            BlockCipher engine = AESEngine.newInstance();
    +            if (lastKey != null)
    +            {
    +                engine.init(true, new KeyParameter(lastKey));
    +            }
    +            return engine;
             }
    -        return engine;
         }
     
         @Override
         public void init(boolean forEncryption, CipherParameters cipherParameters)
                 throws IllegalArgumentException
         {
    -        this.forEncryption = forEncryption;
    -        keptMac = null;
    -        theEncData.reset();
    -
    -        /* Set defaults */
    -        byte[] myInitialAEAD = null;
    -        byte[] myNonce;
    -        KeyParameter myKey;
    -
    -        /* Access parameters */
    -        if (cipherParameters instanceof AEADParameters)
    -        {
    -            final AEADParameters myAEAD = (AEADParameters) cipherParameters;
    -            myInitialAEAD = myAEAD.getAssociatedText();
    -            myNonce = myAEAD.getNonce();
    -            myKey = myAEAD.getKey();
    -        }
    -        else if (cipherParameters instanceof ParametersWithIV)
    -        {
    -            final ParametersWithIV myParms = (ParametersWithIV) cipherParameters;
    -            myNonce = myParms.getIV();
    -            myKey = (KeyParameter) myParms.getParameters();
    -        }
    -        else
    -        {
    -            throw new IllegalArgumentException("invalid parameters passed to GCM-SIV");
    -        }
    -
    -        /* Reset details */
    -        theInitialAEAD = myInitialAEAD;
    -        theNonce = myNonce;
    -        lastKey = myKey.getKey();
    -        switch (lastKey.length)
    +        synchronized (this)
             {
    -            case 16:
    -            case 24:
    -            case 32:
    -                break;
    -            default:
    -                throw new IllegalStateException(ExceptionMessages.AES_KEY_LENGTH);
    +            this.forEncryption = forEncryption;
    +            keptMac = null;
    +            theEncData.reset();
    +
    +            /* Set defaults */
    +            byte[] myInitialAEAD = null;
    +            byte[] myNonce;
    +            KeyParameter myKey;
    +
    +            /* Access parameters */
    +            if (cipherParameters instanceof AEADParameters)
    +            {
    +                final AEADParameters myAEAD = (AEADParameters) cipherParameters;
    +                myInitialAEAD = myAEAD.getAssociatedText();
    +                myNonce = myAEAD.getNonce();
    +                myKey = myAEAD.getKey();
    +            }
    +            else if (cipherParameters instanceof ParametersWithIV)
    +            {
    +                final ParametersWithIV myParms = (ParametersWithIV) cipherParameters;
    +                myNonce = myParms.getIV();
    +                myKey = (KeyParameter) myParms.getParameters();
    +            }
    +            else
    +            {
    +                throw new IllegalArgumentException("invalid parameters passed to GCM-SIV");
    +            }
    +
    +            /* Reset details */
    +            theInitialAEAD = myInitialAEAD;
    +            theNonce = myNonce;
    +            lastKey = myKey.getKey();
    +            switch (lastKey.length)
    +            {
    +                case 16:
    +                case 24:
    +                case 32:
    +                    break;
    +                default:
    +                    throw new IllegalStateException(ExceptionMessages.AES_KEY_LENGTH);
    +            }
    +
    +            initRef();
    +
    +
    +            initNative(
    +                    refWrapper.getReference(),
    +                    forEncryption, lastKey,
    +                    theNonce, theInitialAEAD);
             }
    -
    -        initRef();
    -
    -
    -        initNative(
    -                refWrapper.getReference(),
    -                forEncryption, lastKey,
    -                theNonce, theInitialAEAD);
    -
         }
     
         private void initRef()
    @@ -124,106 +125,131 @@ public String getAlgorithmName()
         @Override
         public void processAADByte(byte in)
         {
    -        if (refWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +            processAADByte(refWrapper.getReference(), in);
             }
    -        processAADByte(refWrapper.getReference(), in);
         }
     
         @Override
         public void processAADBytes(byte[] in, int inOff, int len)
         {
    -        if (refWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +            processAADBytes(refWrapper.getReference(), in, inOff, len);
             }
    -        processAADBytes(refWrapper.getReference(), in, inOff, len);
         }
     
         @Override
         public int processByte(byte in, byte[] out, int outOff)
                 throws DataLengthException
         {
    -        if (refWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +            theEncData.write(in);
    +            return 0;
             }
    -        theEncData.write(in);
    -        return 0;
         }
     
         @Override
         public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
                 throws DataLengthException
         {
    -        if (refWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +            theEncData.write(in, inOff, len);
    +            return 0;
             }
    -        theEncData.write(in, inOff, len);
    -        return 0;
         }
     
         @Override
         public int doFinal(byte[] out, int outOff)
                 throws IllegalStateException, InvalidCipherTextException
         {
    -
    -        int len = doFinal(refWrapper.getReference(), theEncData.getBuffer(), theEncData.size(), out, outOff);
    -        //resetKeepMac
    -        keptMac = getMac();
    -        reset();
    -        return len;
    +        synchronized (this)
    +        {
    +            int len = doFinal(refWrapper.getReference(), theEncData.getBuffer(), theEncData.size(), out, outOff);
    +            //resetKeepMac
    +            keptMac = getMac();
    +            reset();
    +            return len;
    +        }
         }
     
         @Override
         public byte[] getMac()
         {
    -        if (refWrapper == null)
    -        {
    -            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    -        }
    -
    -        if (keptMac != null)
    +        synchronized (this)
             {
    -            return Arrays.clone(keptMac);
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +
    +            if (keptMac != null)
    +            {
    +                return Arrays.clone(keptMac);
    +            }
    +            return getMac(refWrapper.getReference());
             }
    -        return getMac(refWrapper.getReference());
         }
     
         @Override
         public int getUpdateOutputSize(int len)
         {
    -        if (refWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +            return getUpdateOutputSize(refWrapper.getReference(), len, theEncData.size());
             }
    -        return getUpdateOutputSize(refWrapper.getReference(), len, theEncData.size());
         }
     
         @Override
         public int getOutputSize(int len)
         {
    -        if (refWrapper == null)
    +        synchronized (this)
             {
    -            throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            if (refWrapper == null)
    +            {
    +                throw new IllegalStateException(ExceptionMessages.GCM_SIV_UNINITIALIZED);
    +            }
    +            return getOutputSize(refWrapper.getReference(), len);
             }
    -        return getOutputSize(refWrapper.getReference(), len);
         }
     
     
         @Override
         public void reset()
         {
    -
    -        theEncData.clearBuffer();
    -        if (refWrapper == null)
    +        synchronized (this)
             {
    -            // deal with reset being called before init.
    -            return;
    +            theEncData.clearBuffer();
    +            if (refWrapper == null)
    +            {
    +                // deal with reset being called before init.
    +                return;
    +            }
    +            reset(refWrapper.getReference());
             }
    -        reset(refWrapper.getReference());
         }
     
         public String toString()
    
  • core/src/main/java/org/bouncycastle/util/dispose/DisposalDaemon.java+50 22 modified
    @@ -37,22 +37,39 @@ public class DisposalDaemon
     
         static
         {
    -        cleanupDelay = Properties.asInteger(CLEANUP_DELAY_PROP, 5);
    +
    +        String cleanupDelayProp = Properties.getPropertyValue(CLEANUP_DELAY_PROP, "0").trim();
    +        if (cleanupDelayProp.endsWith("ms"))
    +        {
    +            cleanupDelay = Math.max(Long.parseLong(cleanupDelayProp.replace("ms", "")), 0);
    +        }
    +        else
    +        {
    +            cleanupDelay = Math.max(Long.parseLong(cleanupDelayProp) * 1000L, 0);
    +        }
    +
     
             //
             // Clean up executor accepts references that are no longer needed
             // and disposes of them in turn.
             //
    -        cleanupExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory()
    +        if (cleanupDelay > 0)
             {
    -            @Override
    -            public Thread newThread(Runnable r)
    +            cleanupExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactory()
                 {
    -                Thread t = new Thread(r, "BC Cleanup Executor");
    -                t.setDaemon(true);
    -                return t;
    -            }
    -        });
    +                @Override
    +                public Thread newThread(Runnable r)
    +                {
    +                    Thread t = new Thread(r, "BC Cleanup Executor");
    +                    t.setDaemon(true);
    +                    return t;
    +                }
    +            });
    +        }
    +        else
    +        {
    +            cleanupExecutor = null;
    +        }
     
             //
             // Sets up the daemon thread that deals with items on the reference
    @@ -117,23 +134,34 @@ public void run()
                             (ReferenceWrapperWithDisposerRunnable) referenceQueue.remove();
                     refs.remove(item);
     
    -                //
    -                // Delay in order to avoid freeing a reference that the GC has
    -                // decided is unreachable concurrently with its last use.
    -                //
    -                cleanupExecutor.schedule(new Runnable()
    +
    +                if (cleanupExecutor == null)
    +                {
    +                    if (LOG.isLoggable(Level.FINE))
    +                    {
    +                        LOG.fine("Disposed: " + item);
    +                    }
    +                    item.dispose();
    +                }
    +                else
                     {
    -                    @Override
    -                    public void run()
    +                    //
    +                    // Delay in order to avoid freeing a reference that the GC has
    +                    // decided is unreachable concurrently with its last use.
    +                    //
    +                    cleanupExecutor.schedule(new Runnable()
                         {
    -                        if (LOG.isLoggable(Level.FINE))
    +                        @Override
    +                        public void run()
                             {
    -                            LOG.fine("Disposed: " + item);
    +                            if (LOG.isLoggable(Level.FINE))
    +                            {
    +                                LOG.fine("Disposed: " + item);
    +                            }
    +                            item.dispose();
                             }
    -                        item.dispose();
    -                    }
    -                }, cleanupDelay, TimeUnit.SECONDS);
    -
    +                    }, cleanupDelay, TimeUnit.MILLISECONDS);
    +                }
     
                 }
                 catch (InterruptedException iex)
    
  • core/src/main/java/org/bouncycastle/util/test/SimpleTest.java+4 3 modified
    @@ -203,12 +203,12 @@ public TestResult perform()
         public abstract void performTest()
             throws Exception;
     
    -    public static void runTest(Test test)
    +    public static boolean runTest(Test test)
         {
    -        runTest(test, System.out);
    +       return runTest(test, System.out);
         }
     
    -    public static void runTest(Test test, PrintStream out)
    +    public static boolean runTest(Test test, PrintStream out)
         {
             TestResult result = test.perform();
     
    @@ -218,6 +218,7 @@ public static void runTest(Test test, PrintStream out)
             }
             // -DM out.println
             out.println(result);
    +        return result.isSuccessful();
         }
     
         public static void runTests(Test[] tests)
    
  • prov/build.gradle+2 2 modified
    @@ -17,7 +17,7 @@ sourceSets {
         }
         java9 {
             java {
    -            srcDirs = ['src/main/jdk1.9']
    +            srcDirs = ['src/main/jdk1.9','../core/src/main/java9' ]
             }
         }
         java11 {
    @@ -62,7 +62,7 @@ compileJava {
     
     compileJava9Java {
         options.release = 9
    -    options.sourcepath = files(['../core/src/main/java', 'src/main/java', 'src/main/jdk1.9'])
    +    options.sourcepath = files(['../core/src/main/java', 'src/main/java', 'src/main/jdk1.9','../core/src/main/java9'])
     }
     
     compileJava11Java {
    
  • prov/src/test/java/org/bouncycastle/jce/provider/test/SimpleTestTest.java+5 4 modified
    @@ -1,13 +1,13 @@
     package org.bouncycastle.jce.provider.test;
     
    -import java.security.Security;
    -
     import junit.framework.TestCase;
     import org.bouncycastle.jce.provider.BouncyCastleProvider;
     import org.bouncycastle.util.test.SimpleTestResult;
     
    +import java.security.Security;
    +
     public class SimpleTestTest
    -    extends TestCase
    +        extends TestCase
     {
         public void testJCE()
         {
    @@ -22,14 +22,15 @@ public void testJCE()
     
             for (int i = 0; i != tests.length; i++)
             {
    -            SimpleTestResult result = (SimpleTestResult)tests[i].perform();
    +            SimpleTestResult result = (SimpleTestResult) tests[i].perform();
     
                 if (!result.isSuccessful())
                 {
                     if (result.getException() != null)
                     {
                         result.getException().printStackTrace();
                     }
    +                System.out.println("Test failed: " + tests[i]);
                     fail("index " + i + " " + result.toString());
                 }
             }
    
  • README.md+24 4 modified
    @@ -228,10 +228,30 @@ a segfault.
     
     ### Properties
     
    -| Property                               | Values                      | Description                                                                  |
    -|----------------------------------------|-----------------------------|------------------------------------------------------------------------------|
    -| org.bouncycastle.native.cpu_variant    | avx, vaes, vaesf or neon-le | Specify a variant to use  see "Selecting a specific variant" for warnings.   |
    -| org.bouncycastle.packet_cipher_enabled | true or false               | False by default, enable or disable use of packet ciphers where appropriate. |
    +| Property                                | Values                      | Description                                                                                          |
    +|-----------------------------------------|-----------------------------|------------------------------------------------------------------------------------------------------|
    +| org.bouncycastle.native.cpu_variant     | avx, vaes, vaesf or neon-le | Specify a variant to use  see "Selecting a specific variant" for warnings.                           |
    +| org.bouncycastle.packet_cipher_enabled  | true or false               | False by default, enable or disable use of packet ciphers where appropriate.                         |
    +| org.bouncycastle.native.cleanup_delay   | 1000ms / 1                  | Delays freeing of native allocations by the given time in milliseconds or seconds, the default is 0. |
    +
    +
    +### Disposal Daemon / Freeing native allocations
    +The library tacks classes and when they become available for garbage collection, and we free any underlying native allocations.
    +
    +Overly aggressive garbage collectors may signal that a class is available for collection while another thread is accessing
    +that class. On busy multicore machines this may occur during the last call to that class causing use after free situation.
    +
    +To deal with this we have employed either the reachability fence, applicable on java 9 and above or synchronized blocks for
    +java 8.
    +
    +If this proves to be unreliable users can also set a cleanup delay via the ```org.bouncycastle.native.cleanup_delay``` property.
    +For example:
    +
    +```-Dorg.bouncycastle.native.cleanup_delay=10ms``` would set a delay of 10 milliseconds, and
    +```-Dorg.bouncycastle.native.cleanup_delay=1``` would set a delay of 1 second.
    +
    +The default cleanup delay is zero and native allocations will be cleaned up immediately upon notification that the relevant
    +class is available to GC.
     
     
     # Things to watch out for
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.