001/*
002 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.hotspot.replacements;
024
025import static com.oracle.graal.hotspot.HotSpotBackend.*;
026import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
027import jdk.internal.jvmci.common.*;
028import jdk.internal.jvmci.meta.*;
029import sun.misc.*;
030
031import com.oracle.graal.api.replacements.*;
032import com.oracle.graal.compiler.common.spi.*;
033import com.oracle.graal.graph.Node.ConstantNodeParameter;
034import com.oracle.graal.graph.Node.NodeIntrinsic;
035import com.oracle.graal.hotspot.nodes.*;
036import com.oracle.graal.nodes.*;
037import com.oracle.graal.nodes.extended.*;
038import com.oracle.graal.word.*;
039
040// JaCoCo Exclude
041
042/**
043 * Substitutions for {@code com.sun.crypto.provider.CipherBlockChaining} methods.
044 */
045public class CipherBlockChainingSubstitutions {
046
047    private static final long embeddedCipherOffset;
048    private static final long rOffset;
049    private static final Class<?> cipherBlockChainingClass;
050    private static final Class<?> feedbackCipherClass;
051    static {
052        try {
053            // Need to use launcher class path as com.sun.crypto.provider.AESCrypt
054            // is normally not on the boot class path
055            ClassLoader cl = Launcher.getLauncher().getClassLoader();
056
057            feedbackCipherClass = Class.forName("com.sun.crypto.provider.FeedbackCipher", true, cl);
058            embeddedCipherOffset = UnsafeAccess.unsafe.objectFieldOffset(feedbackCipherClass.getDeclaredField("embeddedCipher"));
059
060            cipherBlockChainingClass = Class.forName("com.sun.crypto.provider.CipherBlockChaining", true, cl);
061            rOffset = UnsafeAccess.unsafe.objectFieldOffset(cipherBlockChainingClass.getDeclaredField("r"));
062        } catch (Exception ex) {
063            throw new JVMCIError(ex);
064        }
065    }
066
067    @Fold
068    private static Class<?> getAESCryptClass() {
069        return AESCryptSubstitutions.AESCryptClass;
070    }
071
072    static int encrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
073        Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
074        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, Kind.Object, LocationIdentity.any());
075        if (getAESCryptClass().isInstance(embeddedCipher)) {
076            Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
077            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, true);
078            return inLength;
079        } else {
080            return encrypt(realReceiver, in, inOffset, inLength, out, outOffset);
081        }
082    }
083
084    static int decrypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset) {
085        Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
086        Object embeddedCipher = UnsafeLoadNode.load(realReceiver, embeddedCipherOffset, Kind.Object, LocationIdentity.any());
087        if (in != out && getAESCryptClass().isInstance(embeddedCipher)) {
088            Object aesCipher = PiNode.piCastNonNull(embeddedCipher, AESCryptSubstitutions.AESCryptClass);
089            crypt(realReceiver, in, inOffset, inLength, out, outOffset, aesCipher, false);
090            return inLength;
091        } else {
092            return decrypt(realReceiver, in, inOffset, inLength, out, outOffset);
093        }
094    }
095
096    private static void crypt(Object rcvr, byte[] in, int inOffset, int inLength, byte[] out, int outOffset, Object embeddedCipher, boolean encrypt) {
097        AESCryptSubstitutions.checkArgs(in, inOffset, out, outOffset);
098        Object realReceiver = PiNode.piCastNonNull(rcvr, cipherBlockChainingClass);
099        Object kObject = UnsafeLoadNode.load(embeddedCipher, AESCryptSubstitutions.kOffset, Kind.Object, LocationIdentity.any());
100        Object rObject = UnsafeLoadNode.load(realReceiver, rOffset, Kind.Object, LocationIdentity.any());
101        Word kAddr = Word.fromWordBase(Word.fromObject(kObject).add(arrayBaseOffset(Kind.Byte)));
102        Word rAddr = Word.fromWordBase(Word.fromObject(rObject).add(arrayBaseOffset(Kind.Byte)));
103        Word inAddr = Word.unsigned(ComputeObjectAddressNode.get(in, arrayBaseOffset(Kind.Byte) + inOffset));
104        Word outAddr = Word.unsigned(ComputeObjectAddressNode.get(out, arrayBaseOffset(Kind.Byte) + outOffset));
105        if (encrypt) {
106            encryptAESCryptStub(ENCRYPT, inAddr, outAddr, kAddr, rAddr, inLength);
107        } else {
108            decryptAESCryptStub(DECRYPT, inAddr, outAddr, kAddr, rAddr, inLength);
109        }
110    }
111
112    @NodeIntrinsic(ForeignCallNode.class)
113    public static native void encryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Word key, Word r, int inLength);
114
115    @NodeIntrinsic(ForeignCallNode.class)
116    public static native void decryptAESCryptStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word in, Word out, Word key, Word r, int inLength);
117}