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}