CUDA—使用GPU暴力破解密码

2/10/2017来源:ASP.NET技巧人气:1521

GPU支持大规模的并行加速运算,胜在量上,CPU处理大量的并行运算显得力不从心,它是胜在逻辑上。利用显卡加速的应用越来越多,但如果说GPU即将或最终将替代CPU还有点言过其实,二者最终将优势互补,各尽所能。

使用显卡的无脑并行运算破解密码是一个不错的选择。这里选择一种简单的情况,限定密码是6位纯数字,并且不限定输入次数,这种 情况下可以使用GPU暴力破解,当然仅供娱乐,并无任何实际的应用价值。

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <iostream>
#include "time.h"

using namespace std;

//密码破解入口函数
cudaError_t BreakWithCuda(const int *userKeyWord, int *keyWordByGPU);

//密码破解核函数
__global__ void BreakPasswordKernel(const int *userKeyWord, int *keyWordByGPU)
{
	//获取线程的索引号
	int blockId = blockIdx.y*gridDim.x + blockIdx.x;
	int threadID = blockId*blockDim.x + threadIdx.x;
	if (threadID == *userKeyWord)
	{
		*keyWordByGPU = threadID;
	}
}

int main()
{
	int userWord = 0;  //用户输入的密码
	int keyWordByGPU = 0;  //接收GPU破解的密码
	cout << "请输入你设置的密码(6位阿拉伯数字):" << endl;
	cin >> userWord;
	const int keyWord = userWord;
	getchar();

	//计算耗时变量
	clock_t startTime, endTime;
	startTime = clock();

	cudaError_t cudaStatus = BreakWithCuda(&keyWord, &keyWordByGPU);
	if (cudaStatus != cudaSuccess) {
		fPRintf(stderr, "BreakWithCuda failed!");
		return 1;
	}

	//重置GPU设备
	cudaStatus = cudaDeviceReset();
	if (cudaStatus != cudaSuccess) {
		fprintf(stderr, "cudaDeviceReset failed!");
		return 1;
	}

	cout << "\n经GPU运算破解的用户密码是:" << endl;

	//输出破解的密码,不足6位前补0
	cout.fill('0');
	cout.width(6);  //总长度6位
	cout << keyWordByGPU << endl << endl;

	endTime = clock();  //破解耗时,以秒位单位
	float spendTime = (float)(endTime - startTime) / CLOCKS_PER_SEC;
	cout << "耗时:\n" << spendTime << "seconds" << endl;

	getchar();
	return 0;
}

cudaError_t BreakWithCuda(const int *userKeyword, int *keyWordByGPU)
{
	int *dev_userKeyWord = 0;
	int *dev_keyWordByGPU = 0;
	cudaError_t cudaStatus;

	//选择运行设备
	cudaStatus = cudaSetDevice(0);
	if (cudaStatus != cudaSuccess) {
		fprintf(stderr, "cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?");
		goto Error;
	}

	// 在GUP上分配显存
	cudaStatus = cudaMalloc((void**)&dev_userKeyWord, sizeof(int));
	if (cudaStatus != cudaSuccess) {
		fprintf(stderr, "cudaMalloc failed!");
		goto Error;
	}
	cudaStatus = cudaMalloc((void**)&dev_keyWordByGPU, sizeof(int));
	if (cudaStatus != cudaSuccess) {
		fprintf(stderr, "cudaMalloc failed!");
		goto Error;
	}

	// 把用户输入的密码从主机复制到设备显存上
	cudaStatus = cudaMemcpy(dev_userKeyWord, userKeyword, sizeof(int), cudaMemcpyHostToDevice);
	if (cudaStatus != cudaSuccess) {
		fprintf(stderr, "cudaMemcpy failed!");
		goto Error;
	}

	dim3 grid(100, 100); //创建一个包含100*100个线程块的Grid    
	BreakPasswordKernel << <grid, 100 >> > (dev_userKeyWord, dev_keyWordByGPU);

	// GPU运行错误检查
	cudaStatus = cudaGetLastError();
	if (cudaStatus != cudaSuccess) {
		fprintf(stderr, "BreakPasswordKernel launch failed: %s\n", cudaGetErrorString(cudaStatus));
		goto Error;
	}

	// cudaDeviceSynchronize waits for the kernel to finish, and returns
	// any errors encountered during the launch.
	cudaStatus = cudaDeviceSynchronize();
	if (cudaStatus != cudaSuccess) {
		fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching BreakPasswordKernel!\n", cudaStatus);
		goto Error;
	}

	// 把破解的密码从GPU拷贝到CPU
	cudaStatus = cudaMemcpy(keyWordByGPU, dev_keyWordByGPU, sizeof(int), cudaMemcpyDeviceToHost);
	if (cudaStatus != cudaSuccess) {
		fprintf(stderr, "cudaMemcpy failed!");
		goto Error;
	}

Error:
	cudaFree(dev_keyWordByGPU);
	cudaFree(dev_userKeyWord);

	return cudaStatus;
}

运行后提示用户输入6位密码,第一位可以为0,如果检测到最终破解的密码不足6位,则可以判断用户在第一位输入的数字是0,所以自动在密码前补上0,补足6位

输入的密码第一位或之后若干位为0的情况:

正常情况: