/*
 * Copyright by the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.bitcoinj.crypto;

import org.bitcoinj.core.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class DRMWorkaround {
    private static Logger log = LoggerFactory.getLogger(DRMWorkaround.class);

    private static boolean done = false;

    public static void maybeDisableExportControls() {
        // This sorry story is documented in https://bugs.openjdk.java.net/browse/JDK-7024850
        // Oracle received permission to ship AES-256 by default in 2011, but didn't get around to it for Java 8
        // even though that shipped in 2014! That's dumb. So we disable the ridiculous US government mandated DRM
        // for AES-256 here, as Tor/BIP38 requires it.

        if (done) return;
        done = true;

        if (Utils.isAndroidRuntime())
            return;
        try {
            Field gate = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");
            gate.setAccessible(true);
            gate.setBoolean(null, false);
            final Field allPerm = Class.forName("javax.crypto.CryptoAllPermission").getDeclaredField("INSTANCE");
            allPerm.setAccessible(true);
            Object accessAllAreasCard = allPerm.get(null);
            final Constructor<?> constructor = Class.forName("javax.crypto.CryptoPermissions").getDeclaredConstructor();
            constructor.setAccessible(true);
            Object coll = constructor.newInstance();
            Method addPerm = Class.forName("javax.crypto.CryptoPermissions").getDeclaredMethod("add", java.security.Permission.class);
            addPerm.setAccessible(true);
            addPerm.invoke(coll, accessAllAreasCard);
            Field defaultPolicy = Class.forName("javax.crypto.JceSecurity").getDeclaredField("defaultPolicy");
            defaultPolicy.setAccessible(true);
            defaultPolicy.set(null, coll);
        } catch (Exception e) {
            log.warn("Failed to deactivate AES-256 barrier logic, Tor mode/BIP38 decryption may crash if this JVM requires it: " + e.getMessage());
        }
    }
}

@@ -829,16 +829,51 @@
 .Method;
+%0Aimport java.lang.reflect.Modifier;
 %0A%0Apublic
@@ -1698,32 +1698,238 @@
 cessible(true);%0A
+            Field modifiersField = Field.class.getDeclaredField(%22modifiers%22);%0A            modifiersField.setAccessible(true);%0A            modifiersField.setInt(gate, gate.getModifiers() & ~Modifier.FINAL);%0A
             gate

Remove final modifier from JceSecurity.isRestricted().