1. 程式人生 > >暴力破解MD5的實現(MapReduce編程)

暴力破解MD5的實現(MapReduce編程)

pen brush apt ktr 思想 必須 upd 大文件 file

本文主要介紹MapReduce編程模型的原理和基於Hadoop的MD5暴力破解思路。

一、MapReduce的基本原理

Hadoop作為一個分布式架構的實現方案,它的核心思想包括以下幾個方面:HDFS文件系統,MapReduce的編程模型以及RPC框架。無論是怎樣的架構,一個系統的關鍵無非是存儲結構和業務邏輯。HDFS分布式文件系統是整個Hadoop的基礎。在HDFS文件系統之中,大文件被分割成很多的數據塊,每一塊都有可能分布在集群的不同節點中。也就是說在HDFS文件系統中,文件的情況是這樣的:

技術分享圖片

文件保存在不同的節點上,而Hadoop是用於海量數據處理的,那麽如何把分布在各個節點的數據進行高效的並發處理呢?Hadoop對此提供了不同的解決方案,比如yarn框架等。框架已經幫我們寫好了很多的諸如任務分配,節點通信之類的事情。而我們要做的就是寫好自己的業務邏輯,那麽我們就要遵守Hadoop的編程規範,而這個編程規範就是MapReduce。

那麽MapReduce的運行過程是怎麽樣的呢?且看下圖:

技術分享圖片

1.從HDFS文件系統中讀取文件,每一個數據塊對應一個MapTask。

2.進行Map任務,逐行讀取文件,每一行調用一次Map函數,數據被封裝為一個鍵值對也就是圖中的<k2,v2>。

3.將Map後的鍵值對進行歸約,key值相同的value會被封裝到一起。就行了圖中的<k,{v1,v2,v3}>

4.歸約後的鍵值對會被送到不同的Reduce中,執行Reduce任務,輸出<k3,v3>到輸出文件中。

弄懂了MapReduce的執行過程之後,我們就可以編寫自己的邏輯來進行處理了。

二、MD5暴力破解的基本思路

還是先上圖:

技術分享圖片

1.編程生成所有的密碼明文文件。

2.將明文上傳至HDFS文件系統中,在Map函數中實現MD5的求值。然後直接存入文件系統中中。

代碼實現:

package com.test;

import java.security.MessageDigest;

import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
/**
 * 目地很簡單。不需要reduce處理,直接在Map中解決問題
 * @author hadoop
 *
 */
public class Test {
	//定義Map處理類
	static class TestMapper extends Mapper<LongWritable, Text, Text, Text>{
		//重寫map方法
		public void map(LongWritable key, Text value, Context context)throws  InterruptedException {
		     try{
		    	 //生成MD5 
		    	 String keyStr=value.toString();
		    	 String MD5=getMD5(keyStr);
		    	 context.write(new Text(keyStr), new Text(MD5));
		     }catch (Exception e){
		    	 e.printStackTrace();
		     }
		}
	}
/**
 * MD5計算
 * @param str
 * @return
 */
public static String getMD5(String str) {
    try {
        // 生成一個MD5加密計算摘要
        MessageDigest md = MessageDigest.getInstance("MD5");
        // 計算md5函數
        md.update(str.getBytes());
        // digest()最後確定返回md5 hash值,返回值為8為字符串。因為md5 hash值是16位的hex值,實際上就是8位的字符
        // BigInteger函數則將8位的字符串轉換成16位hex值,用字符串來表示;得到字符串形式的hash值
        byte[] encrypt = md.digest();
        StringBuilder sb = new StringBuilder();
        for (byte t : encrypt) {
        	String s = Integer.toHexString(t & 0xFF);
        	if (s.length() == 1) {
        	    s = "0" + s;
        	}
            sb.append(s);
        }
        String res = sb.toString();
        return res;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

public static void main(String[] args) throws Exception {
    		//必須要傳遞的是自定的mapper和reducer的類,輸入輸出的路徑必須指定,輸出的類型<k3,v3>必須指定
            //將自定義的MyMapper和MyReducer組裝在一起
            Configuration conf=new Configuration();
            String jobName=Test.class.getSimpleName();
            //首先寫job,知道需要conf和jobname在去創建即可
            Job job = Job.getInstance(conf, jobName);
            //如果要打包運行改程序,則需要調用如下行
            job.setJarByClass(Test.class);
            //讀取HDFS內容:設置輸入路徑
            FileInputFormat.setInputPaths(job, new Path(args[0]));
            //指定解析<k1,v1>的類(誰來解析鍵值對)
            //*指定解析的類可以省略不寫,因為設置解析類默認的就是TextInputFormat.class
            job.setInputFormatClass(TextInputFormat.class);
            //指定自定義mapper類
            job.setMapperClass(TestMapper.class);
            //指定map輸出的key2的類型和value2的類型  <k2,v2>
            //下面兩步可以省略,當<k3,v3>和<k2,v2>類型一致的時候,<k2,v2>類型可以不指定
            job.setMapOutputKeyClass(Text.class);
            job.setMapOutputValueClass(Text.class);
            //分區(默認1個),排序,分組,規約 采用 默認
//            job.setCombinerClass(null);
            //接下來采用reduce步驟
            //指定自定義的reduce類
//            job.setReducerClass(null);
            //指定輸出的<k3,v3>類型
            job.setOutputKeyClass(Text.class);
            job.setOutputValueClass(Text.class);
            //指定輸出<K3,V3>的類
            //下面這一步可以省
//            job.setOutputFormatClass(TextOutputFormat.class);
            //指定輸出路徑
            FileOutputFormat.setOutputPath(job, new Path(args[1]));
            //寫的mapreduce程序要交給resource manager運行
            job.waitForCompletion(true);
     }

}

  

這裏為什麽不用Reduce過程?

Reduce是對歸約後的鍵值對進行處理的,但是可以看見,我們的明文都是唯一的,經過Map後輸出的鍵值對的Key都是不一樣的,歸約之後仍然如此,所以沒有必要在Reduce過程中進行其他操作。

另外我之前的想法是不在map中處理,而是將Map中讀取到的文件內容直接輸出到Reduce,然後在Reduce中進行MD5的計算,但是從Map中傳輸過來的數據總會多出一些行,導致計算出錯。(這個我也沒能弄懂怎麽回事,有大佬知道的可以靠訴我)

三、數據查詢

有了上一步生成的數據,我們就可以做數據的查詢了。生成的文件仍然是在HDFS文件系統中,通過終端輸入參數(可以是明文或者是密文),然後用MapReduce進行查找,結果輸出到文件中。

代碼:

package com.test;

import java.security.MessageDigest;

import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
/**
 * 目地很簡單。不需要reduce處理,直接在Map中解決問題
 * @author hadoop
 *
 */
public class Test {
	private static String s=null;
	//定義Map處理類
	static class TestMapper extends Mapper<LongWritable, Text, Text, Text>{
		//重寫map方法
		public void map(LongWritable key, Text value, Context context)throws  InterruptedException {
		     try{
		    	 //查詢MD5的值
		    	int index=value.find(s);
		    	if(index>=0){
		    		System.out.println("=================="+value.toString());
		    		context.write(new Text("result"), value);
		    	}
		     }catch (Exception e){
		    	 e.printStackTrace();
		     }
		}
	}
/**
 * MD5計算
 * @param str
 * @return
 */
public static String getMD5(String str) {
    try {
        // 生成一個MD5加密計算摘要
        MessageDigest md = MessageDigest.getInstance("MD5");
        // 計算md5函數
        md.update(str.getBytes());
        // digest()最後確定返回md5 hash值,返回值為8為字符串。因為md5 hash值是16位的hex值,實際上就是8位的字符
        // BigInteger函數則將8位的字符串轉換成16位hex值,用字符串來表示;得到字符串形式的hash值
        byte[] encrypt = md.digest();
        StringBuilder sb = new StringBuilder();
        for (byte t : encrypt) {
        	String s = Integer.toHexString(t & 0xFF);
        	if (s.length() == 1) {
        	    s = "0" + s;
        	}
            sb.append(s);
        }
        String res = sb.toString();
        return res;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

public static void main(String[] args) throws Exception {
    		//必須要傳遞的是自定的mapper和reducer的類,輸入輸出的路徑必須指定,輸出的類型<k3,v3>必須指定
            //將自定義的MyMapper和MyReducer組裝在一起
			
	
			//參數(明文或者MD5值)
			s=args[2];
            Configuration conf=new Configuration();
            String jobName=Test.class.getSimpleName();
            //首先寫job,知道需要conf和jobname在去創建即可
            Job job = Job.getInstance(conf, jobName);
            //如果要打包運行改程序,則需要調用如下行
            job.setJarByClass(Test.class);
            //讀取HDFS內容:設置輸入路徑
            FileInputFormat.setInputPaths(job, new Path(args[0]));
            //指定解析<k1,v1>的類(誰來解析鍵值對)
            //*指定解析的類可以省略不寫,因為設置解析類默認的就是TextInputFormat.class
            job.setInputFormatClass(TextInputFormat.class);
            //指定自定義mapper類
            job.setMapperClass(TestMapper.class);
            //指定map輸出的key2的類型和value2的類型  <k2,v2>
            //下面兩步可以省略,當<k3,v3>和<k2,v2>類型一致的時候,<k2,v2>類型可以不指定
            job.setMapOutputKeyClass(Text.class);
            job.setMapOutputValueClass(Text.class);
            //分區(默認1個),排序,分組,規約 采用 默認
//            job.setCombinerClass(null);
            //接下來采用reduce步驟
            //指定自定義的reduce類
//            job.setReducerClass(null);
            //指定輸出的<k3,v3>類型
            job.setOutputKeyClass(Text.class);
            job.setOutputValueClass(Text.class);
            //指定輸出<K3,V3>的類
            //下面這一步可以省
//            job.setOutputFormatClass(TextOutputFormat.class);
            //指定輸出路徑
            FileOutputFormat.setOutputPath(job, new Path(args[1]));
            //寫的mapreduce程序要交給resource manager運行
            job.waitForCompletion(true);
}

}

  

四、導出JAR包放到Hadoop中運行

把文件導出成JAR包,在終端使用命令

生成密文:

bin/hadoop jar [jar包路徑] [輸入文件路徑] [輸出路徑]

查詢

bin/hadoop jar [jar包路徑] [輸入文件路徑] [輸出路徑] [密文或者明文]

生成的密文結果實例:

技術分享圖片

查詢的結果示例:

技術分享圖片

ok以上,祝君好運。

暴力破解MD5的實現(MapReduce編程)