`

Java构建HashCode相同字符串算法

    博客分类:
  • jdk
 
阅读更多
import java.math.BigDecimal;  
import java.util.Random;  

/**
“中间相遇法”是生日攻击的一种变形,它不比较Hash值,而是比较链中的中间变量。这种攻击主要适用于攻击具有分组链结构的Hash方案。中间相遇攻击的基本原理为:将消息分成两部分,对伪造消息的第一部分从初试值开始逐步向中间阶段产生r1个变量;对伪造消息的第二部分从Hash结果开始逐步退回中间阶段产生r2个变量。在中间阶段有一个匹配的概率与生日攻击成功的概率一样。
*/  
public class HashCollide {  
  
    /** 
     * 拼凑字符的起始值(最后实际值可能为 collideCharBase +- mulBase) 
     */  
    private int collideCharBase;  
  
    /** 
     * 中间变量 
     */  
    private BigDecimal collideCharBase_decimal;  
  
    /** 
     * 中间变量 
     */  
    private BigDecimal mulBase_decimal_pow;  
  
    /** 
     * 拼凑字符串长度 
     */  
    private int collideCharLength;  
  
    /** 
     * hash算法中采用的乘积值 (hash' = hash * mulBase + char[i]) 
     */  
    private long mulBase;  
  
    /** 
     * 中间变量 
     */  
    private BigDecimal mulBase_decimal;  
  
    /** 
     * 中间变量 
     */  
    private long mulBase_desc;  
  
    /** 
     * 中间变量 
     */  
    private BigDecimal mulBase_desc_decimal;  
  
    /** 
     * 2的轮回... 
     */  
    private final long INT_ROUTE_NUMBER = 2l << 32;  
  
    /** 
     * 还是2的轮回... 
     */  
    private final BigDecimal DECIMAL_ROUTE_NUMBER = new BigDecimal(  
            INT_ROUTE_NUMBER);  
  
    /** 
     * 不知道干啥的,好奇怪 
     */  
    private final Random random = new Random(System.nanoTime());  
  
    /** 
     * 测试你的char数组能吧srcHash变成什么样子 
     *  
     * @param srcHash 
     * @param collide 
     * @return 
     */  
    public int hashCodeTest(int srcHash, char collide[]) {  
        int h = srcHash;  
        int len = collide.length;  
        for (int i = 0; i < len; i++) {  
            h = (int) mulBase * h + collide[i];  
        }  
        return h;  
    }  
  
    /** 
     * 根据这个类构造时设置的参数输出hash 
     *  
     * @param srcString 
     * @return 
     */  
    public int hashCodeTest(String srcString) {  
        char[] chars = srcString.toCharArray();  
  
        int h = 0;  
        int len = chars.length;  
        for (int i = 0; i < len; i++) {  
            h = (int) mulBase * h + chars[i];  
        }  
        return h;  
    }  
  
    /** 
     * 将一个decimal的值通过取余转换成一个属于int范围的long 
     *  
     * @param data 
     * @return 
     */  
    private long fixDecimal(BigDecimal data) {  
        // 求余数  
        BigDecimal sub = data.divideToIntegralValue(DECIMAL_ROUTE_NUMBER  
                .multiply(DECIMAL_ROUTE_NUMBER));  
  
        // 可能为负数,修正为long类型之后再次求余  
        long val = data.subtract(sub).longValue();  
        val += INT_ROUTE_NUMBER;  
        val = val % INT_ROUTE_NUMBER;  
  
        if (val < 0) // val应该不会小于0  
            val += INT_ROUTE_NUMBER;  
        return val;  
    }  
  
    /** 
     * 把val转换为正序的char数组,用以表示一个n位k进制数据 
     *  
     * @param val 
     * @return 
     */  
    private char[] offsetToArray(long val) {  
        char[] stk = new char[collideCharLength];  
        int pos = 0;  
  
        while (val != 0) { // 进制转换,得到反序列  
            stk[pos++] = (char) (val % (mulBase) + collideCharBase);  
            val = val / mulBase;  
        }  
  
        int fillZero = collideCharLength - pos; // 补零的个数  
        char[] collides = new char[collideCharLength];  
        int i = 0;  
        while (i < fillZero) { // 高位补零  
            collides[i++] = (char) collideCharBase;  
        }  
  
        while (i < collideCharLength) { // 逐位反向输出  
            collides[i] = stk[pos - i + fillZero - 1]; // pos - ( i - fillZero )  
            ++i;  
        }  
  
        return collides;  
    }  
  
    /** 
     * 根据hash的src和target生成一组序列,使原串后面附加序列字符后的hash与target相同 
     *  
     * @param src 
     * @param target 
     * @param collideCharBase 
     * @param n 
     * @return 
     */  
    private char[] genCollisionArray(int src, int target) {  
        long hx = mulBase_desc * src + collideCharBase;  
        BigDecimal halfCal = mulBase_decimal_pow.multiply(new BigDecimal(hx)) // 中间变量  
                .subtract(collideCharBase_decimal);  
        BigDecimal left = halfCal.divide(mulBase_desc_decimal); // 依然是中间变量  
        BigDecimal fix = new BigDecimal(target).subtract(left); // 还是中间变量,不过这次是修正数据  
  
        long fixedDecimal = fixDecimal(fix);  
  
        return offsetToArray(fixedDecimal);  
    }  
  
    /** 
     * 构造函数 
     *  
     * @param collideCharBase 
     *            拼凑字符的起始值(最后实际值可能为 collideCharBase +- mulBase) 
     * @param collideCharLength 
     *            拼凑字符串长度 
     * @param mulBase 
     *            hash算法中采用的乘积值 (hash' = hash * mulBase + char[i]) 
     */  
    public HashCollide(int collideCharBase, int collideCharLength, int mulBase) {  
        this.mulBase = mulBase;  
        this.mulBase_decimal = new BigDecimal(mulBase);  
        this.mulBase_desc = mulBase - 1;  
        this.mulBase_desc_decimal = new BigDecimal(mulBase - 1);  
  
        this.mulBase_decimal_pow = mulBase_decimal.pow(collideCharLength);  
  
        this.collideCharBase = collideCharBase;  
        this.collideCharBase_decimal = new BigDecimal(collideCharBase);  
        this.collideCharLength = collideCharLength;  
  
    }  
  
    /** 
     * ... 
     *  
     * @param source 
     * @param targetHash 
     * @return 
     */  
    public String collide(String source, int targetHash) {  
        int hashSrc = source.hashCode();  
        char[] collide = this.genCollisionArray(hashSrc, targetHash);  
        return source.concat(new String(collide));  
    }  
  
    /** 
     * ... 
     *  
     * @return 
     */  
    public String randomString(int length) {  
        char[] chars = new char[length];  
        for (int i = 0; i < length; ++i) {  
            chars[i] = (char) (50 + random.nextInt(32 + 26 + 15));  
        }  
        return new String(chars);  
    }  
  
    public static void main(String[] args) {  
  
    	System.out.println("NH]n;<pFEP2R4DYDw4Fsg^Z[gTHIx=e4H:hSEVtfR^SqsP]y[gK_:gIgvZccbUmj".hashCode());
    	System.out.println("W@3Lb=SIr`\\h?KT5?ayLtd37y]x=\\Pcibr4O4SaKubhJ_M`lqEbjk;5ycYmZp^cm".hashCode());

    	System.out.println("====================");
    	
    	HashCollide collide = new HashCollide(85, 7, 31);  
    	
    	for (int i = 0; i < 10000; ++i) {  
    		
    		String a = collide.randomString(57);  
    		String b = collide.collide(a, 912366222);  
    		System.out.println(b);  
    		
    		if (b.hashCode() != 912366222) {  
    			System.err.println("ERROR :: src = " + a);  
    			System.err.println("ERROR :: dst = " + b); 
    			System.exit(1);  
    		}
    	}
    	  
    }  





JDK String.hashCode()

  
 /**
     * Returns a hash code for this string. The hash code for a
     * <code>String</code> object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using <code>int</code> arithmetic, where <code>s[i]</code> is the
     * <i>i</i>th character of the string, <code>n</code> is the length of
     * the string, and <code>^</code> indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */
    public int hashCode() {
	int h = hash;
	if (h == 0) {
	    int off = offset;
	    char val[] = value;
	    int len = count;

            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++]; //31 上文构造方法参数mulBase
            }
            hash = h;
        }
        return h;
    }

分享到:
评论
1 楼 yzjdt 2019-05-24  
请问一下,这个代码我看了半天,也debug研究了一下,为什么collideCharLength(拼凑字符串的长度),一定不能小于7呢?

相关推荐

    Java语言与面向对象程序设计第06讲(字符串)

    - **StringBuffer类**:可变的字符串对象,适合在多线程环境中进行字符串的构建和修改,避免创建多个String对象。 6. **递归**:在第3章已经介绍,是函数调用自身的技术,常用于解决分治问题和树形结构的问题。 7...

    java实习周记25篇.docx

    在这个项目中,Collection框架用于存储和操作数据,例如顾客的队列、业务类型等,体现了Java在数据结构和算法上的应用。通过实习,作者不仅深化了理论知识,还积累了实践经验,为后续的Java开发工作奠定了坚实基础。

    10种java性能优化方案.docx

    1. **StringBuilder的使用**:相比于字符串连接操作,使用`StringBuilder`可以大幅提高字符串构建的效率。 2. **其他建议**: - **缓存机制**:合理使用缓存可以减少数据库访问次数,从而提高性能。 - **数据库...

    Java实现和维护系统详解.pdf

    1. **使用StringBuilder或StringBuffer**:在处理字符串连接时,避免使用"+"操作符,因为它会在每次连接时创建新的字符串对象,而StringBuilder和StringBuffer则提供了一种更高效的动态构建字符串的方式。...

    java面试笔记整理,包含java,redis,kafka等

    - **StringJoiner用于连接字符串,提供了一种更简洁的方式来构建复合字符串。** #### 十九、String类常用方法 - **length():** 返回字符串长度。 - **charAt(int index):** 返回指定索引处的字符。 - **concat...

    jdk17-java17

    为了简化多行字符串的编写,Java 17引入了文本块,避免了过多的转义字符和字符串连接操作。 13. **安全性更新**: 包括对加密算法、SSL/TLS协议以及Java Cryptography Architecture(JCA)的改进,提升了安全标准...

    java API中文版

    `Object`类是所有类的父类,它定义了一些基本的方法,如`equals()`用于比较对象是否相等,`toString()`返回对象的字符串表示,以及`hashCode()`用于计算对象的哈希值。`System`类提供了一些系统级别的服务,如获取...

    JAVA SE概要点总结

    Java的流程控制包括顺序结构、选择结构(if、if-else、if-else if...else、switch,JDK7支持字符串switch)和循环结构(while、do-while、for、for-each)。同时,流程跳转涉及`break`、`continue`和`return`。 **7...

    javastring赋值笔试题-CodeForInterview:面试整理的一些基础知识点,从summary.md开始阅读

    - 除了《剑指Offer》,还有其他优秀书籍推荐,如《算法导论》、《编程珠玑》等,它们都包含丰富的字符串处理和算法问题。 理解并熟练掌握这些Java字符串的知识点,将有助于你在面试中展现出扎实的基础和解决问题的...

    面试题及答案.docx

    - 判断相关:`equals()`和`equalsIgnoreCase()`比较字符串内容是否相同,`contains()`检查字符串是否包含指定内容,`startsWith()`和`endsWith()`检查是否以特定字符或字符串开头或结尾。 - 内容改变:`...

    commons-lang常用

    它支持添加任意数量的对象属性到构建器中,最终生成一个清晰的字符串表示形式。 综上所述,`commons-lang`库以其丰富的实用工具类,极大地提升了Java开发的效率和代码质量,是每个Java开发者不可或缺的工具箱之一。

    java api大集合

    `String`类用于处理文本字符串,提供了大量的操作方法,如拼接、查找、替换等。`System`类则包含了一些系统相关的属性和方法,如获取当前时间或退出程序。 2. **集合框架**: `java.util`包中的集合框架是Java API的...

    java私塾学习笔记整理

    Object类是所有Java类的基类,包含一些基本方法如`equals()`、`toString()`、`hashCode()`等。 **二、String类** String类表示字符串,它是不可变的。提供了多种方法用于操作字符串。 **三、正则表达式** Java...

    java面试题目 想要的拿去吧

    常量池中的字符串比较时,可以直接通过“==”来比较其引用是否相等,从而判断两个字符串是否相同。而对于堆上的字符串对象,则需通过`equals()`方法来比较其内容是否相等。 #### 三、`try-finally`语句中的返回值...

    Java后端技术面试基础汇总

    - `StringBuilder`和`StringBuffer`用于构建字符串,后者是线程安全的。 - **重载和重写:** - 重载发生在同一个类内,方法名相同但参数列表不同。 - 重写发生在继承关系中,子类覆盖父类的方法。 - **抽象类和...

    java编码规范资料

    - **字符串比较**:使用`equals()`方法而非`==`来比较字符串内容是否相同,因为后者只检查引用是否指向同一个对象。 - **字符串替换**:对于频繁的字符串替换操作,可以考虑使用`replace()`或`replaceAll()`方法。 ...

    Java面试题

    ### Java面试题详解 ...以上知识点覆盖了Java基础语法、集合框架、数据库操作、对象创建、字符串处理、垃圾回收、异常处理以及Java Web开发等多个方面,是Java程序员面试和日常工作中不可或缺的核心技能。

    02-Java语言进阶_javase_

    Object类提供了如equals()、hashCode()和toString()等基本方法,用于对象的比较、哈希值计算和字符串表示。 2. **常用API**:Java API包含了大量预定义的类和接口,如集合框架、IO流、网络编程、多线程等。掌握这些...

Global site tag (gtag.js) - Google Analytics