/* * FindBugs - Find Bugs in Java programs * Copyright (C) 2003-2008 University of Maryland * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package edu.umd.cs.findbugs; import java.math.BigInteger; import java.security.MessageDigest; import java.util.Iterator; import edu.umd.cs.findbugs.ba.SignatureParser; import edu.umd.cs.findbugs.internalAnnotations.DottedClassName; /** * @author pugh */ public class Obfuscate { final static String HASH_SEED = SystemProperties.getProperty("hashSeed", ""); public static String hashData(String in) { MessageDigest md; try { md = MessageDigest.getInstance("SHA-1"); byte[] hash = md.digest((HASH_SEED + in).getBytes("UTF-8")); return String.format("%040x", new BigInteger(1, hash)); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } public static String hashFilename(String fileName) { int lastDot = fileName.lastIndexOf('.'); if (lastDot >= 0) { String suffix = fileName.substring(lastDot); return hashData(fileName.substring(0, lastDot)) + suffix; } return hashData(fileName); } public static String hashClass(@DottedClassName String className) { if (className.startsWith("java")) return className; return "obfuscated.H" + hashData(className); } public static String hashSignature(String signature) { char firstChar = signature.charAt(0); switch (firstChar) { case '[': return '[' + hashSignature(signature.substring(1)); case 'V': case 'Z': case 'B': case 'S': case 'C': case 'I': case 'J': case 'D': case 'F': if (signature.length() == 1) return signature; throw new IllegalArgumentException("bad signature: " + signature); case 'L': if (!signature.endsWith(";")) throw new IllegalArgumentException("bad signature: " + signature); return hashFieldSignature(signature); default: throw new IllegalArgumentException("bad signature: " + signature); } } public static String hashFieldSignature(String signature) { signature = signature.substring(1, signature.length() - 1); if (!signature.startsWith("java")) signature = "obfuscated/H" + hashData(signature); return "L" + signature + ";"; } public static String hashMethodSignature(String signature) { SignatureParser parser = new SignatureParser(signature); StringBuilder buf = new StringBuilder("("); for (Iterator<String> i = parser.parameterSignatureIterator(); i.hasNext();) { String param = i.next(); buf.append(hashSignature(param)); } buf.append(")"); buf.append(hashSignature(parser.getReturnTypeSignature())); return buf.toString(); } static MethodAnnotation obfuscate(MethodAnnotation m) { String className = m.getClassName(); if (className.startsWith("java")) return m; String methodName = m.getMethodName(); String methodSignature = m.getMethodSignature(); if (methodName.equals("hashCode") && methodSignature.equals("()I") || methodName.equals("equals") && methodSignature.equals("(Ljava/lang/Object;)Z") || methodName.equals("compareTo") && methodSignature.equals("(Ljava/lang/Object;)I") || methodName.equals("<init>") || methodName.equals("<clinit>")) { // don't need to obfuscate method name } else { methodName = hashData(methodName); } MethodAnnotation result = new MethodAnnotation(hashClass(className), methodName, hashMethodSignature(methodSignature), m.isStatic()); result.setDescription(m.getDescription()); return result; } static FieldAnnotation obfuscate(FieldAnnotation m) { FieldAnnotation result = new FieldAnnotation(hashClass(m.getClassName()), hashData(m.getFieldName()), hashSignature(m.getFieldSignature()), m.isStatic()); result.setDescription(m.getDescription()); return result; } static ClassAnnotation obfuscate(ClassAnnotation m) { ClassAnnotation result = new ClassAnnotation(hashClass(m.getClassName())); result.setDescription(m.getDescription()); return result; } static TypeAnnotation obfuscate(TypeAnnotation m) { TypeAnnotation result = new TypeAnnotation(hashSignature(m.getTypeDescriptor())); result.setDescription(m.getDescription()); return result; } static IntAnnotation obfuscate(IntAnnotation m) { IntAnnotation result = new IntAnnotation(m.getValue()); result.setDescription(m.getDescription()); return result; } static StringAnnotation obfuscate(StringAnnotation m) { StringAnnotation result = new StringAnnotation("obfuscated: " + hashData(m.getValue())); result.setDescription(m.getDescription()); return result; } static SourceLineAnnotation obfuscate(SourceLineAnnotation m) { SourceLineAnnotation result = new SourceLineAnnotation(hashClass(m.getClassName()), hashFilename(m.getSourceFile()), m.getStartLine(), m.getEndLine(), m.getStartBytecode(), m.getEndBytecode()); result.setDescription(m.getDescription()); return result; } static LocalVariableAnnotation obfuscate(LocalVariableAnnotation m) { LocalVariableAnnotation result = new LocalVariableAnnotation(hashData(m.getName()), m.getRegister(), m.getPC()); result.setDescription(m.getDescription()); return result; } public static BugInstance obfuscate(BugInstance b) { final BugInstance result = new BugInstance(b.getType(), b.getPriority()); BugAnnotationVisitor visitor = new BugAnnotationVisitor() { public void visitTypeAnnotation(TypeAnnotation typeAnnotation) { result.add(obfuscate(typeAnnotation)); } public void visitStringAnnotation(StringAnnotation stringAnnotation) { result.add(obfuscate(stringAnnotation)); } public void visitSourceLineAnnotation(SourceLineAnnotation sourceLineAnnotation) { result.add(obfuscate(sourceLineAnnotation)); } public void visitMethodAnnotation(MethodAnnotation methodAnnotation) { result.add(obfuscate(methodAnnotation)); } public void visitLocalVariableAnnotation(LocalVariableAnnotation fieldAnnotation) { result.add(obfuscate(fieldAnnotation)); } public void visitIntAnnotation(IntAnnotation fieldAnnotation) { result.add(obfuscate(fieldAnnotation)); } public void visitFieldAnnotation(FieldAnnotation fieldAnnotation) { result.add(obfuscate(fieldAnnotation)); } public void visitClassAnnotation(ClassAnnotation classAnnotation) { result.add(obfuscate(classAnnotation)); } }; for (BugAnnotation a : b.getAnnotations()) a.accept(visitor); result.setOldInstanceHash(hashData(b.getInstanceHash())); result.setHistory(b); return result; } }