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

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

1、MapReduce的基本原理

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

文件保存在不一樣的節點上,而Hadoop是用於海量數據處理的,那麼如何把分佈在各個節點的數據進行高效的併發處理呢?Hadoop對此提供了不一樣的解決方案,好比yarn框架等。框架已經幫咱們寫好了不少的諸如任務分配,節點通訊之類的事情。而咱們要作的就是寫好本身的業務邏輯,那麼咱們就要遵照Hadoop的編程規範,而這個編程規範就是MapReduce。編程

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

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

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

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

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

弄懂了MapReduce的執行過程以後,咱們就能夠編寫本身的邏輯來進行處理了。函數

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

仍是先上圖:oop

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中傳輸過來的數據總會多出一些行,致使計算出錯。(這個我也沒能弄懂怎麼回事,有大佬知道的能夠靠訴我)

3、數據查詢

有了上一步生成的數據,咱們就能夠作數據的查詢了。生成的文件仍然是在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);
}

}

  

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

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

生成密文:

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

查詢

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

生成的密文結果實例:

查詢的結果示例:

ok以上,祝君好運。

相關文章
相關標籤/搜索