- 전체
- HTML
- Web Design (웹디자인)
- XE 응용 개발
- wordpress plugin dev
- Javascript & JavaScript Application
- MEAN Stack : full stack javascript
- angular js & ionic framework
- bootstrap
- WebGL, Three.js and Babylon.js
- restful api design
- mobile web
- node.js 응용
- Cloud Service 응용
- 웹 어셈블리 개발 [WASM, WebAssembly]
- 마이크로서비스, MSA (microservice architecture)
- WebGL / WebGPU
- next.js 개발
- micro frontend (마이크로프론트앤드)
[php worldpress] [위 에]wordpress 사용자 암호 화 원리 및 알고리즘 분석
[설명]본 글 은 학습 교류 에 만 사용 되 며 상업 용도 로 사용 하지 마 십시오.현지 법 규 를 위반 하지 마 십시오.그렇지 않 으 면 결 과 는 스스로 책임 져 야 합 니 다.
전재 본 논문 의 출처 를 밝 혀 주 십시오.http://blog.csdn.net/hk_jh/article/details/27368279
1.워드 프레스 가 무엇 입 니까?
워드 프레스 에 대한 소 개 는 위 키 피 디 아 를 참조 하 시기 바 랍 니 다.http://zh.wikipedia.org/wiki/Wordpress
사실 암호 화 원 리 를 파악 하고 효율 적 인 언어 로 이 루어 지면 폭력 적 인 해결 이 쉽 지 않 겠 습 니까?
2.wordpress 사용자 암호 화 알고리즘
우선,워드 프레스 는 오픈 소스 입 니 다.홈 페이지 에서 소스 코드 를 다운로드 할 수 있 습 니 다.또한 wordpress 는 php 언어 로 작 성 된 것 입 니 다.
wordpress 사용자 암호 화 후의 암호 화 형식:
$P$BcSda3/tRXQcRZMPj3cUI0jZJFdMgL0 $P$BNclJc4wbM.vSjKPYxKggDPtw3siXQ0
다음은 압축 해제 후 폴 더/include 의 class-phopass.phop 파일 의 코드 입 니 다.주로 사용자 암 호 를 암호 화 하 는 클래스 와 함 수 를 포함 합 니 다.
<?php
/**
* Portable PHP password hashing framework.
* @package phpass
* @since 2.5.0
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
*/
#
# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
# the public domain. Revised in subsequent years, still public domain.
#
# There's absolutely no warranty.
#
# Please be sure to update the Version line if you edit this file in any way.
# It is suggested that you leave the main version number intact, but indicate
# your project name (after the slash) and add your own revision information.
#
# Please do not change the "private" password hashing method implemented in
# here, thereby making your hashes incompatible. However, if you must, please
# change the hash type identifier (the "$P$") to something different.
#
# Obviously, since this code is in the public domain, the above are not
# requirements (there can be none), but merely suggestions.
#
/**
* Portable PHP password hashing framework.
*
* @package phpass
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
* @since 2.5.0
*/
class PasswordHash {
var $itoa64;
var $iteration_count_log2;
var $portable_hashes;
var $random_state;
function PasswordHash($iteration_count_log2, $portable_hashes)
{
$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
$iteration_count_log2 = 8;
$this->iteration_count_log2 = $iteration_count_log2;
$this->portable_hashes = $portable_hashes;
$this->random_state = microtime() . uniqid(rand(), TRUE); // removed getmypid() for compatibility reasons
}
function get_random_bytes($count)
{
$output = '';
if ( @is_readable('/dev/urandom') &&
($fh = @fopen('/dev/urandom', 'rb'))) {
$output = fread($fh, $count);
fclose($fh);
}
if (strlen($output) < $count) {
$output = '';
for ($i = 0; $i < $count; $i += 16) {
$this->random_state =
md5(microtime() . $this->random_state);
$output .=
pack('H*', md5($this->random_state));
}
$output = substr($output, 0, $count);
}
return $output;
}
function encode64($input, $count)
{
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
function gensalt_private($input)
{
$output = '$P$';
$output .= $this->itoa64[min($this->iteration_count_log2 +
((PHP_VERSION >= '5') ? 5 : 3), 30)];
$output .= $this->encode64($input, 6);
return $output;
}
function crypt_private($password, $setting)
{
$output = '*0';
if (substr($setting, 0, 2) == $output)
$output = '*1';
$id = substr($setting, 0, 3);
# We use "$P$", phpBB3 uses "$H$" for the same thing
if ($id != '$P$' && $id != '$H$')
return $output;
$count_log2 = strpos($this->itoa64, $setting[3]);
if ($count_log2 < 7 || $count_log2 > 30)
return $output;
$count = 1 << $count_log2;
$salt = substr($setting, 4, 8);
if (strlen($salt) != 8)
return $output;
# We're kind of forced to use MD5 here since it's the only
# cryptographic primitive available in all versions of PHP
# currently in use. To implement our own low-level crypto
# in PHP would result in much worse performance and
# consequently in lower iteration counts and hashes that are
# quicker to crack (by non-PHP code).
if (PHP_VERSION >= '5') {
$hash = md5($salt . $password, TRUE);
do {
$hash = md5($hash . $password, TRUE);
} while (--$count);
} else {
$hash = pack('H*', md5($salt . $password));
do {
$hash = pack('H*', md5($hash . $password));
} while (--$count);
}
$output = substr($setting, 0, 12);
$output .= $this->encode64($hash, 16);
return $output;
}
function gensalt_extended($input)
{
$count_log2 = min($this->iteration_count_log2 + 8, 24);
# This should be odd to not reveal weak DES keys, and the
# maximum valid value is (2**24 - 1) which is odd anyway.
$count = (1 << $count_log2) - 1;
$output = '_';
$output .= $this->itoa64[$count & 0x3f];
$output .= $this->itoa64[($count >> 6) & 0x3f];
$output .= $this->itoa64[($count >> 12) & 0x3f];
$output .= $this->itoa64[($count >> 18) & 0x3f];
$output .= $this->encode64($input, 3);
return $output;
}
function gensalt_blowfish($input)
{
# This one needs to use a different order of characters and a
# different encoding scheme from the one in encode64() above.
# We care because the last character in our encoded string will
# only represent 2 bits. While two known implementations of
# bcrypt will happily accept and correct a salt string which
# has the 4 unused bits set to non-zero, we do not want to take
# chances and we also do not want to waste an additional byte
# of entropy.
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '17072a$';
$output .= chr(ord('0') + $this->iteration_count_log2 / 10);
$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
$output .= '$';
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (1);
return $output;
}
function HashPassword($password)
{
$random = '';
if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
$random = $this->get_random_bytes(16);
$hash =
crypt($password, $this->gensalt_blowfish($random));
if (strlen($hash) == 60)
return $hash;
}
if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
if (strlen($random) < 3)
$random = $this->get_random_bytes(3);
$hash =
crypt($password, $this->gensalt_extended($random));
if (strlen($hash) == 20)
return $hash;
}
if (strlen($random) < 6)
$random = $this->get_random_bytes(6);
$hash =
$this->crypt_private($password,
$this->gensalt_private($random));
if (strlen($hash) == 34)
return $hash;
# Returning '*' on error is safe here, but would _not_ be safe
# in a crypt(3)-like function used _both_ for generating new
# hashes and for validating passwords against existing hashes.
return '*';
}
function CheckPassword($password, $stored_hash)
{
$hash = $this->crypt_private($password, $stored_hash);
if ($hash[0] == '*')
$hash = crypt($password, $stored_hash);
return $hash === $stored_hash;
}
}
?>
3.알고리즘 분석
(1)wordpress 암호 화 된 비밀문서 형식:$P$B12345678huiyw4r7qhfuhs8yjmd6ef$P2345678huiyw4r7qhfuhs8yjmd6ef 1 단:$P$형식 고정 2 단:한 글자 만 있 습 니 다.phop 버 전이 5.0 이상 이면 B 이 고 그렇지 않 으 면 9 세 번 째 단계 입 니 다.8 비트 salt 네 번 째 단계:22 비트,실제 암호 화 된 암호 화 방법 phop 버 전 은 5.0 보다 높 습 니 다.
$hash = md5($salt . $password, TRUE);
do
{
$hash = md5($hash . $password, TRUE);
} while (--$count);
[주]"."php 에서 연결 연산 입 니 다.
파라미터 TRUR 는 암호 화 결 과 를 16 바이트 바 이 너 리 로 표시 합 니 다.
count 2 의 13 차방:8192
php 버 전 5.0 이하
$hash = pack('H*', md5($salt . $password));
do
{
$hash = pack('H*', md5($hash . $password));
} while (--$count);
[주]phop 이 5.0 md5 보다 낮 으 면 32 비트 16 진수 문자열 형식 으로 돌아 갑 니 다.
pack(H*)은 md5 결 과 를 2 진법 으로 바꾼다.
count 취 2 의 11 차방:2048
상기 방법 으로 얻 은$hash 를 base 64 암호 화 합 니 다:
(3)wordpress 의 base 64 알고리즘
64 비트 문자 표 는 특수 합 니 다.일반적인 문자 표 순서 와 차이 가 있 습 니 다.
itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
//input 즉 hash,count=16
function encode64($input, $count)
{
$output = '';
$i = 0;
do
{
$value = ord($input[$i++]);// acsii
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
상기 방법 으로 22 비트 암호 화 된 비밀 번 호 를 얻 을 수 있 습 니 다.
4.C 로 wordpress 의 암호 화 실현
다음은 본인 이 C 로 구현 한 코드 입 니 다.오류 가 있 으 면 지적 해 주 십시오!
wordpress.c 파일:
#include <stdio.h>
#include <string.h>
#include "md5.h"
#include "wordpress.h"
#define WORDPRESS_MD5_CHAR_NUM 16
unsigned char base64Char[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
void md5_to_unsigned_char(unsigned char *hash)
{
int i;
unsigned char md5[17];
for (i = 0; i < 16; i++)
{
if (hash[2*i] >= '0' && hash[2*i] <= '9')
md5[i] = (hash[2*i] - '0') << 4;
else if (hash[2*i] >= 'a' && hash[2*i] <= 'f')
md5[i] = (hash[2*i] - 'a') <<4;
if (hash[2*i+1] >= '0' && hash[2*i+1] <= '9')
md5[i] = md5[i] | ((hash[2*i+1] - '0') & 0x0f);
else if (hash[2*i+1] >= 'a' && hash[2*i+1] <= 'f')
md5[i] = md5[i] | ((hash[2*i+1] - 'a') & 0x0f);
}
md5[16] = '[php worldpress] [위 에]wordpress 사용자 암호 화 원리 및 알고리즘 분석
[설명]본 글 은 학습 교류 에 만 사용 되 며 상업 용도 로 사용 하지 마 십시오.현지 법 규 를 위반 하지 마 십시오.그렇지 않 으 면 결 과 는 스스로 책임 져 야 합 니 다.
전재 본 논문 의 출처 를 밝 혀 주 십시오.http://blog.csdn.net/hk_jh/article/details/27368279
1.워드 프레스 가 무엇 입 니까?
워드 프레스 에 대한 소 개 는 위 키 피 디 아 를 참조 하 시기 바 랍 니 다.http://zh.wikipedia.org/wiki/Wordpress
사실 암호 화 원 리 를 파악 하고 효율 적 인 언어 로 이 루어 지면 폭력 적 인 해결 이 쉽 지 않 겠 습 니까?
2.wordpress 사용자 암호 화 알고리즘
우선,워드 프레스 는 오픈 소스 입 니 다.홈 페이지 에서 소스 코드 를 다운로드 할 수 있 습 니 다.또한 wordpress 는 php 언어 로 작 성 된 것 입 니 다.
wordpress 사용자 암호 화 후의 암호 화 형식:
$P$BcSda3/tRXQcRZMPj3cUI0jZJFdMgL0 $P$BNclJc4wbM.vSjKPYxKggDPtw3siXQ0
다음은 압축 해제 후 폴 더/include 의 class-phopass.phop 파일 의 코드 입 니 다.주로 사용자 암 호 를 암호 화 하 는 클래스 와 함 수 를 포함 합 니 다.
<?php
/**
* Portable PHP password hashing framework.
* @package phpass
* @since 2.5.0
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
*/
#
# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
# the public domain. Revised in subsequent years, still public domain.
#
# There's absolutely no warranty.
#
# Please be sure to update the Version line if you edit this file in any way.
# It is suggested that you leave the main version number intact, but indicate
# your project name (after the slash) and add your own revision information.
#
# Please do not change the "private" password hashing method implemented in
# here, thereby making your hashes incompatible. However, if you must, please
# change the hash type identifier (the "$P$") to something different.
#
# Obviously, since this code is in the public domain, the above are not
# requirements (there can be none), but merely suggestions.
#
/**
* Portable PHP password hashing framework.
*
* @package phpass
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
* @since 2.5.0
*/
class PasswordHash {
var $itoa64;
var $iteration_count_log2;
var $portable_hashes;
var $random_state;
function PasswordHash($iteration_count_log2, $portable_hashes)
{
$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
$iteration_count_log2 = 8;
$this->iteration_count_log2 = $iteration_count_log2;
$this->portable_hashes = $portable_hashes;
$this->random_state = microtime() . uniqid(rand(), TRUE); // removed getmypid() for compatibility reasons
}
function get_random_bytes($count)
{
$output = '';
if ( @is_readable('/dev/urandom') &&
($fh = @fopen('/dev/urandom', 'rb'))) {
$output = fread($fh, $count);
fclose($fh);
}
if (strlen($output) < $count) {
$output = '';
for ($i = 0; $i < $count; $i += 16) {
$this->random_state =
md5(microtime() . $this->random_state);
$output .=
pack('H*', md5($this->random_state));
}
$output = substr($output, 0, $count);
}
return $output;
}
function encode64($input, $count)
{
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
function gensalt_private($input)
{
$output = '$P$';
$output .= $this->itoa64[min($this->iteration_count_log2 +
((PHP_VERSION >= '5') ? 5 : 3), 30)];
$output .= $this->encode64($input, 6);
return $output;
}
function crypt_private($password, $setting)
{
$output = '*0';
if (substr($setting, 0, 2) == $output)
$output = '*1';
$id = substr($setting, 0, 3);
# We use "$P$", phpBB3 uses "$H$" for the same thing
if ($id != '$P$' && $id != '$H$')
return $output;
$count_log2 = strpos($this->itoa64, $setting[3]);
if ($count_log2 < 7 || $count_log2 > 30)
return $output;
$count = 1 << $count_log2;
$salt = substr($setting, 4, 8);
if (strlen($salt) != 8)
return $output;
# We're kind of forced to use MD5 here since it's the only
# cryptographic primitive available in all versions of PHP
# currently in use. To implement our own low-level crypto
# in PHP would result in much worse performance and
# consequently in lower iteration counts and hashes that are
# quicker to crack (by non-PHP code).
if (PHP_VERSION >= '5') {
$hash = md5($salt . $password, TRUE);
do {
$hash = md5($hash . $password, TRUE);
} while (--$count);
} else {
$hash = pack('H*', md5($salt . $password));
do {
$hash = pack('H*', md5($hash . $password));
} while (--$count);
}
$output = substr($setting, 0, 12);
$output .= $this->encode64($hash, 16);
return $output;
}
function gensalt_extended($input)
{
$count_log2 = min($this->iteration_count_log2 + 8, 24);
# This should be odd to not reveal weak DES keys, and the
# maximum valid value is (2**24 - 1) which is odd anyway.
$count = (1 << $count_log2) - 1;
$output = '_';
$output .= $this->itoa64[$count & 0x3f];
$output .= $this->itoa64[($count >> 6) & 0x3f];
$output .= $this->itoa64[($count >> 12) & 0x3f];
$output .= $this->itoa64[($count >> 18) & 0x3f];
$output .= $this->encode64($input, 3);
return $output;
}
function gensalt_blowfish($input)
{
# This one needs to use a different order of characters and a
# different encoding scheme from the one in encode64() above.
# We care because the last character in our encoded string will
# only represent 2 bits. While two known implementations of
# bcrypt will happily accept and correct a salt string which
# has the 4 unused bits set to non-zero, we do not want to take
# chances and we also do not want to waste an additional byte
# of entropy.
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '$2a$';
$output .= chr(ord('0') + $this->iteration_count_log2 / 10);
$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
$output .= '$';
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (1);
return $output;
}
function HashPassword($password)
{
$random = '';
if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
$random = $this->get_random_bytes(16);
$hash =
crypt($password, $this->gensalt_blowfish($random));
if (strlen($hash) == 60)
return $hash;
}
if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
if (strlen($random) < 3)
$random = $this->get_random_bytes(3);
$hash =
crypt($password, $this->gensalt_extended($random));
if (strlen($hash) == 20)
return $hash;
}
if (strlen($random) < 6)
$random = $this->get_random_bytes(6);
$hash =
$this->crypt_private($password,
$this->gensalt_private($random));
if (strlen($hash) == 34)
return $hash;
# Returning '*' on error is safe here, but would _not_ be safe
# in a crypt(3)-like function used _both_ for generating new
# hashes and for validating passwords against existing hashes.
return '*';
}
function CheckPassword($password, $stored_hash)
{
$hash = $this->crypt_private($password, $stored_hash);
if ($hash[0] == '*')
$hash = crypt($password, $stored_hash);
return $hash === $stored_hash;
}
}
?>
3.알고리즘 분석
(1)wordpress 암호 화 된 비밀문서 형식:$P$B12345678huiyw4r7qhfuhs8yjmd6ef$P$912345678huiyw4r7qhfuhs8yjmd6ef 1 단:$P$형식 고정 2 단:한 글자 만 있 습 니 다.phop 버 전이 5.0 이상 이면 B 이 고 그렇지 않 으 면 9 세 번 째 단계 입 니 다.8 비트 salt 네 번 째 단계:22 비트,실제 암호 화 된 암호 화 방법 phop 버 전 은 5.0 보다 높 습 니 다.
$hash = md5($salt . $password, TRUE);
do
{
$hash = md5($hash . $password, TRUE);
} while (--$count);
[주]"."php 에서 연결 연산 입 니 다.
파라미터 TRUR 는 암호 화 결 과 를 16 바이트 바 이 너 리 로 표시 합 니 다.
count 2 의 13 차방:8192
php 버 전 5.0 이하
$hash = pack('H*', md5($salt . $password));
do
{
$hash = pack('H*', md5($hash . $password));
} while (--$count);
[주]phop 이 5.0 md5 보다 낮 으 면 32 비트 16 진수 문자열 형식 으로 돌아 갑 니 다.
pack(H*)은 md5 결 과 를 2 진법 으로 바꾼다.
count 취 2 의 11 차방:2048
상기 방법 으로 얻 은$hash 를 base 64 암호 화 합 니 다:
(3)wordpress 의 base 64 알고리즘
64 비트 문자 표 는 특수 합 니 다.일반적인 문자 표 순서 와 차이 가 있 습 니 다.
itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
//input 즉 hash,count=16
function encode64($input, $count)
{
$output = '';
$i = 0;
do
{
$value = ord($input[$i++]);// acsii
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
상기 방법 으로 22 비트 암호 화 된 비밀 번 호 를 얻 을 수 있 습 니 다.
4.C 로 wordpress 의 암호 화 실현
다음은 본인 이 C 로 구현 한 코드 입 니 다.오류 가 있 으 면 지적 해 주 십시오!
wordpress.c 파일:
#include <stdio.h>
#include <string.h>
#include "md5.h"
#include "wordpress.h"
#define WORDPRESS_MD5_CHAR_NUM 16
unsigned char base64Char[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
void md5_to_unsigned_char(unsigned char *hash)
{
int i;
unsigned char md5[17];
for (i = 0; i < 16; i++)
{
if (hash[2*i] >= '0' && hash[2*i] <= '9')
md5[i] = (hash[2*i] - '0') << 4;
else if (hash[2*i] >= 'a' && hash[2*i] <= 'f')
md5[i] = (hash[2*i] - 'a') <<4;
if (hash[2*i+1] >= '0' && hash[2*i+1] <= '9')
md5[i] = md5[i] | ((hash[2*i+1] - '0') & 0x0f);
else if (hash[2*i+1] >= 'a' && hash[2*i+1] <= 'f')
md5[i] = md5[i] | ((hash[2*i+1] - 'a') & 0x0f);
}
md5[16] = '\0';
for (i = 0; i < 16; i++)
hash[i] = md5[i];
hash[16] = '\0';
}
void base64Encode(unsigned char *md5, unsigned char *result)
{
int num_24bits = 5;
int i;
for (i = 0; i < num_24bits; ++i)
{
result[4 * i + 0] = base64Char[(md5[3 * i] >> 2) & 0x3F];
result[4 * i + 1] = base64Char[(((md5[3 * i] & 0x3) << 4) | (md5[3 * i + 1] >> 4)) & 0x3F];
result[4 * i + 2] = base64Char[((md5[3 * i + 1] << 2) | (md5[3 * i + 2] >> 6)) & 0x3F];
result[4 * i + 3] = base64Char[md5[3 * i + 2] & 0x3F];
}
result[20] = base64Char[md5[15] >> 2];
result[21] = base64Char[(md5[15] << 4) & 0x3F];
result[22] = '\0';
}
int wordpress( unsigned char * salt, unsigned char *passwd, int count, unsigned char *code )
{
int i, j;
char symbol;
unsigned char buffer[100];
unsigned char base64_code[23];
int len = strlen( (char *)passwd );
if (strlen( (char *)salt ) != 8)
{
printf("illegal salt!
");
return 1;
}
if (count != 8192 && count != 2048)
{
printf("illegal count!
");
return 1;
}
//first time use md5 function with salt
strcpy( (char *)buffer, (char *)salt );
strcat( (char *)buffer, (char *)passwd );
MD5( buffer, strlen( (char *)buffer), buffer, 0 );
md5_to_unsigned_char( buffer );
//count times md5 function
for (i = 0; i < count; i++)
{
memcpy( (void *)&buffer[WORDPRESS_MD5_CHAR_NUM], passwd, len );
MD5( buffer, WORDPRESS_MD5_CHAR_NUM + len, buffer, 0 );
md5_to_unsigned_char( buffer );
}
memcpy( (void *)code, buffer, 32);
base64Encode( buffer, base64_code );
if (count == 8192)
symbol = 'B';
else if(count == 2048)
symbol = '9';
strcpy( (char *)code, "$P$" );
code[3] = symbol;
code[4] = '\0';
strcat( (char *)code, (char *)salt);
memcpy( (void *)&code[12], base64_code, 22);
return 0;
}
이전에 자신 이 쓴 md5 코드 를 동봉 합 니 다:
#include "md5.h"
#include <stdio.h>
#include <memory.h>
#include <string.h>
#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x^y^z)
#define I(x,y,z) (y ^ (x | ~z))
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
#define FF(a,b,c,d,x,s,ac) \
{ \
a += F(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define GG(a,b,c,d,x,s,ac) \
{ \
a += G(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define HH(a,b,c,d,x,s,ac) \
{ \
a += H(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define II(a,b,c,d,x,s,ac) \
{ \
a += I(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
void MD5Init(MD5_CTX *context);
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);
void MD5Final(MD5_CTX *context,unsigned char digest[16]);
void MD5Transform(unsigned int state[4],unsigned char block[64]);
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len);
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len);
unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
void MD5Init(MD5_CTX *context)
{
context->count[0] = 0;
context->count[1] = 0;
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
}
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)
{
unsigned int i = 0,index = 0,partlen = 0;
index = (context->count[0] >> 3) & 0x3F;
partlen = 64 - index;
context->count[0] += inputlen << 3;
if(context->count[0] < (inputlen << 3))
context->count[1]++;
context->count[1] += inputlen >> 29;
if(inputlen >= partlen)
{
memcpy(&context->buffer[index],input,partlen);
MD5Transform(context->state,context->buffer);
for(i = partlen;i+64 <= inputlen;i+=64)
MD5Transform(context->state,&input[i]);
index = 0;
}
else
{
i = 0;
}
memcpy(&context->buffer[index],&input[i],inputlen-i);
}
void MD5Final(MD5_CTX *context,unsigned char digest[16])
{
unsigned int index = 0,padlen = 0;
unsigned char bits[8];
index = (context->count[0] >> 3) & 0x3F;
padlen = (index < 56)?(56-index):(120-index);
MD5Encode(bits,context->count,8);
MD5Update(context,PADDING,padlen);
MD5Update(context,bits,8);
MD5Encode(digest,context->state,16);
}
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[j] = input[i] & 0xFF;
output[j+1] = (input[i] >> 8) & 0xFF;
output[j+2] = (input[i] >> 16) & 0xFF;
output[j+3] = (input[i] >> 24) & 0xFF;
i++;
j+=4;
}
}
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[i] = (input[j]) |
(input[j+1] << 8) |
(input[j+2] << 16) |
(input[j+3] << 24);
i++;
j+=4;
}
}
void MD5Transform(unsigned int state[4],unsigned char block[64])
{
unsigned int a = state[0];
unsigned int b = state[1];
unsigned int c = state[2];
unsigned int d = state[3];
unsigned int x[64];
MD5Decode(x,block,64);
FF(a, b, c, d, x[ 0], 7, 0xd76aa478);
FF(d, a, b, c, x[ 1], 12, 0xe8c7b756);
FF(c, d, a, b, x[ 2], 17, 0x242070db);
FF(b, c, d, a, x[ 3], 22, 0xc1bdceee);
FF(a, b, c, d, x[ 4], 7, 0xf57c0faf);
FF(d, a, b, c, x[ 5], 12, 0x4787c62a);
FF(c, d, a, b, x[ 6], 17, 0xa8304613);
FF(b, c, d, a, x[ 7], 22, 0xfd469501);
FF(a, b, c, d, x[ 8], 7, 0x698098d8);
FF(d, a, b, c, x[ 9], 12, 0x8b44f7af);
FF(c, d, a, b, x[10], 17, 0xffff5bb1);
FF(b, c, d, a, x[11], 22, 0x895cd7be);
FF(a, b, c, d, x[12], 7, 0x6b901122);
FF(d, a, b, c, x[13], 12, 0xfd987193);
FF(c, d, a, b, x[14], 17, 0xa679438e);
FF(b, c, d, a, x[15], 22, 0x49b40821);
GG(a, b, c, d, x[ 1], 5, 0xf61e2562);
GG(d, a, b, c, x[ 6], 9, 0xc040b340);
GG(c, d, a, b, x[11], 14, 0x265e5a51);
GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa);
GG(a, b, c, d, x[ 5], 5, 0xd62f105d);
GG(d, a, b, c, x[10], 9, 0x2441453);
GG(c, d, a, b, x[15], 14, 0xd8a1e681);
GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8);
GG(a, b, c, d, x[ 9], 5, 0x21e1cde6);
GG(d, a, b, c, x[14], 9, 0xc33707d6);
GG(c, d, a, b, x[ 3], 14, 0xf4d50d87);
GG(b, c, d, a, x[ 8], 20, 0x455a14ed);
GG(a, b, c, d, x[13], 5, 0xa9e3e905);
GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8);
GG(c, d, a, b, x[ 7], 14, 0x676f02d9);
GG(b, c, d, a, x[12], 20, 0x8d2a4c8a);
HH(a, b, c, d, x[ 5], 4, 0xfffa3942);
HH(d, a, b, c, x[ 8], 11, 0x8771f681);
HH(c, d, a, b, x[11], 16, 0x6d9d6122);
HH(b, c, d, a, x[14], 23, 0xfde5380c);
HH(a, b, c, d, x[ 1], 4, 0xa4beea44);
HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9);
HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60);
HH(b, c, d, a, x[10], 23, 0xbebfbc70);
HH(a, b, c, d, x[13], 4, 0x289b7ec6);
HH(d, a, b, c, x[ 0], 11, 0xeaa127fa);
HH(c, d, a, b, x[ 3], 16, 0xd4ef3085);
HH(b, c, d, a, x[ 6], 23, 0x4881d05);
HH(a, b, c, d, x[ 9], 4, 0xd9d4d039);
HH(d, a, b, c, x[12], 11, 0xe6db99e5);
HH(c, d, a, b, x[15], 16, 0x1fa27cf8);
HH(b, c, d, a, x[ 2], 23, 0xc4ac5665);
II(a, b, c, d, x[ 0], 6, 0xf4292244);
II(d, a, b, c, x[ 7], 10, 0x432aff97);
II(c, d, a, b, x[14], 15, 0xab9423a7);
II(b, c, d, a, x[ 5], 21, 0xfc93a039);
II(a, b, c, d, x[12], 6, 0x655b59c3);
II(d, a, b, c, x[ 3], 10, 0x8f0ccc92);
II(c, d, a, b, x[10], 15, 0xffeff47d);
II(b, c, d, a, x[ 1], 21, 0x85845dd1);
II(a, b, c, d, x[ 8], 6, 0x6fa87e4f);
II(d, a, b, c, x[15], 10, 0xfe2ce6e0);
II(c, d, a, b, x[ 6], 15, 0xa3014314);
II(b, c, d, a, x[13], 21, 0x4e0811a1);
II(a, b, c, d, x[ 4], 6, 0xf7537e82);
II(d, a, b, c, x[11], 10, 0xbd3af235);
II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb);
II(b, c, d, a, x[ 9], 21, 0xeb86d391);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
void MD5(unsigned char * buf, unsigned int len, unsigned char *out, int type)
{
int i;
MD5_CTX md5;
unsigned char digest[16];
char hex[]="0123456789abcdef";
char HEX[]="0123456789ABCDEF";
MD5Init(&md5);
MD5Update(&md5, buf,len);
MD5Final(&md5, digest);
if (type == 0)
{
for (i = 0; i < 16; i++)
{
out[i+i] = hex[digest[i] >> 4];
out[i+i+1] = hex[digest[i] & 0x0f];
}
}
else if (type == 1)
{
for (i = 0; i < 16; i++)
{
out[i+i] = HEX[digest[i] >> 4];
out[i+i+1] = HEX[digest[i] & 0x0f];
}
}
out[i+i] = '\0';
}
테스트 코드:
#include <stdio.h>
#include "wordpress.h"
int main()
{
unsigned char passwd[] = "12345678";
unsigned char salt[] = "12345687";
unsigned char code[40];
wordpress(salt, passwd, 8192, code);
printf("code: %s
", code);
return 0;
}
[출처] https://intrepidgeeks.com/tutorial/part-1-analysis-of-wordpress-user-encryption-principle-and-algorithm
[php worldpress] [위 에]wordpress 사용자 암호 화 원리 및 알고리즘 분석
[설명]본 글 은 학습 교류 에 만 사용 되 며 상업 용도 로 사용 하지 마 십시오.현지 법 규 를 위반 하지 마 십시오.그렇지 않 으 면 결 과 는 스스로 책임 져 야 합 니 다.
전재 본 논문 의 출처 를 밝 혀 주 십시오.http://blog.csdn.net/hk_jh/article/details/27368279
1.워드 프레스 가 무엇 입 니까?
워드 프레스 에 대한 소 개 는 위 키 피 디 아 를 참조 하 시기 바 랍 니 다.http://zh.wikipedia.org/wiki/Wordpress
사실 암호 화 원 리 를 파악 하고 효율 적 인 언어 로 이 루어 지면 폭력 적 인 해결 이 쉽 지 않 겠 습 니까?
2.wordpress 사용자 암호 화 알고리즘
우선,워드 프레스 는 오픈 소스 입 니 다.홈 페이지 에서 소스 코드 를 다운로드 할 수 있 습 니 다.또한 wordpress 는 php 언어 로 작 성 된 것 입 니 다.
wordpress 사용자 암호 화 후의 암호 화 형식:
$P$BcSda3/tRXQcRZMPj3cUI0jZJFdMgL0 $P$BNclJc4wbM.vSjKPYxKggDPtw3siXQ0
다음은 압축 해제 후 폴 더/include 의 class-phopass.phop 파일 의 코드 입 니 다.주로 사용자 암 호 를 암호 화 하 는 클래스 와 함 수 를 포함 합 니 다.
<?php
/**
* Portable PHP password hashing framework.
* @package phpass
* @since 2.5.0
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
*/
#
# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
# the public domain. Revised in subsequent years, still public domain.
#
# There's absolutely no warranty.
#
# Please be sure to update the Version line if you edit this file in any way.
# It is suggested that you leave the main version number intact, but indicate
# your project name (after the slash) and add your own revision information.
#
# Please do not change the "private" password hashing method implemented in
# here, thereby making your hashes incompatible. However, if you must, please
# change the hash type identifier (the "$P$") to something different.
#
# Obviously, since this code is in the public domain, the above are not
# requirements (there can be none), but merely suggestions.
#
/**
* Portable PHP password hashing framework.
*
* @package phpass
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
* @since 2.5.0
*/
class PasswordHash {
var $itoa64;
var $iteration_count_log2;
var $portable_hashes;
var $random_state;
function PasswordHash($iteration_count_log2, $portable_hashes)
{
$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
$iteration_count_log2 = 8;
$this->iteration_count_log2 = $iteration_count_log2;
$this->portable_hashes = $portable_hashes;
$this->random_state = microtime() . uniqid(rand(), TRUE); // removed getmypid() for compatibility reasons
}
function get_random_bytes($count)
{
$output = '';
if ( @is_readable('/dev/urandom') &&
($fh = @fopen('/dev/urandom', 'rb'))) {
$output = fread($fh, $count);
fclose($fh);
}
if (strlen($output) < $count) {
$output = '';
for ($i = 0; $i < $count; $i += 16) {
$this->random_state =
md5(microtime() . $this->random_state);
$output .=
pack('H*', md5($this->random_state));
}
$output = substr($output, 0, $count);
}
return $output;
}
function encode64($input, $count)
{
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
function gensalt_private($input)
{
$output = '$P$';
$output .= $this->itoa64[min($this->iteration_count_log2 +
((PHP_VERSION >= '5') ? 5 : 3), 30)];
$output .= $this->encode64($input, 6);
return $output;
}
function crypt_private($password, $setting)
{
$output = '*0';
if (substr($setting, 0, 2) == $output)
$output = '*1';
$id = substr($setting, 0, 3);
# We use "$P$", phpBB3 uses "$H$" for the same thing
if ($id != '$P$' && $id != '$H$')
return $output;
$count_log2 = strpos($this->itoa64, $setting[3]);
if ($count_log2 < 7 || $count_log2 > 30)
return $output;
$count = 1 << $count_log2;
$salt = substr($setting, 4, 8);
if (strlen($salt) != 8)
return $output;
# We're kind of forced to use MD5 here since it's the only
# cryptographic primitive available in all versions of PHP
# currently in use. To implement our own low-level crypto
# in PHP would result in much worse performance and
# consequently in lower iteration counts and hashes that are
# quicker to crack (by non-PHP code).
if (PHP_VERSION >= '5') {
$hash = md5($salt . $password, TRUE);
do {
$hash = md5($hash . $password, TRUE);
} while (--$count);
} else {
$hash = pack('H*', md5($salt . $password));
do {
$hash = pack('H*', md5($hash . $password));
} while (--$count);
}
$output = substr($setting, 0, 12);
$output .= $this->encode64($hash, 16);
return $output;
}
function gensalt_extended($input)
{
$count_log2 = min($this->iteration_count_log2 + 8, 24);
# This should be odd to not reveal weak DES keys, and the
# maximum valid value is (2**24 - 1) which is odd anyway.
$count = (1 << $count_log2) - 1;
$output = '_';
$output .= $this->itoa64[$count & 0x3f];
$output .= $this->itoa64[($count >> 6) & 0x3f];
$output .= $this->itoa64[($count >> 12) & 0x3f];
$output .= $this->itoa64[($count >> 18) & 0x3f];
$output .= $this->encode64($input, 3);
return $output;
}
function gensalt_blowfish($input)
{
# This one needs to use a different order of characters and a
# different encoding scheme from the one in encode64() above.
# We care because the last character in our encoded string will
# only represent 2 bits. While two known implementations of
# bcrypt will happily accept and correct a salt string which
# has the 4 unused bits set to non-zero, we do not want to take
# chances and we also do not want to waste an additional byte
# of entropy.
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '$2a$';
$output .= chr(ord('0') + $this->iteration_count_log2 / 10);
$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
$output .= '$';
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (1);
return $output;
}
function HashPassword($password)
{
$random = '';
if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
$random = $this->get_random_bytes(16);
$hash =
crypt($password, $this->gensalt_blowfish($random));
if (strlen($hash) == 60)
return $hash;
}
if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
if (strlen($random) < 3)
$random = $this->get_random_bytes(3);
$hash =
crypt($password, $this->gensalt_extended($random));
if (strlen($hash) == 20)
return $hash;
}
if (strlen($random) < 6)
$random = $this->get_random_bytes(6);
$hash =
$this->crypt_private($password,
$this->gensalt_private($random));
if (strlen($hash) == 34)
return $hash;
# Returning '*' on error is safe here, but would _not_ be safe
# in a crypt(3)-like function used _both_ for generating new
# hashes and for validating passwords against existing hashes.
return '*';
}
function CheckPassword($password, $stored_hash)
{
$hash = $this->crypt_private($password, $stored_hash);
if ($hash[0] == '*')
$hash = crypt($password, $stored_hash);
return $hash === $stored_hash;
}
}
?>
3.알고리즘 분석
(1)wordpress 암호 화 된 비밀문서 형식:$P$B12345678huiyw4r7qhfuhs8yjmd6ef$P$912345678huiyw4r7qhfuhs8yjmd6ef 1 단:$P$형식 고정 2 단:한 글자 만 있 습 니 다.phop 버 전이 5.0 이상 이면 B 이 고 그렇지 않 으 면 9 세 번 째 단계 입 니 다.8 비트 salt 네 번 째 단계:22 비트,실제 암호 화 된 암호 화 방법 phop 버 전 은 5.0 보다 높 습 니 다.
$hash = md5($salt . $password, TRUE);
do
{
$hash = md5($hash . $password, TRUE);
} while (--$count);
[주]"."php 에서 연결 연산 입 니 다.
파라미터 TRUR 는 암호 화 결 과 를 16 바이트 바 이 너 리 로 표시 합 니 다.
count 2 의 13 차방:8192
php 버 전 5.0 이하
$hash = pack('H*', md5($salt . $password));
do
{
$hash = pack('H*', md5($hash . $password));
} while (--$count);
[주]phop 이 5.0 md5 보다 낮 으 면 32 비트 16 진수 문자열 형식 으로 돌아 갑 니 다.
pack(H*)은 md5 결 과 를 2 진법 으로 바꾼다.
count 취 2 의 11 차방:2048
상기 방법 으로 얻 은$hash 를 base 64 암호 화 합 니 다:
(3)wordpress 의 base 64 알고리즘
64 비트 문자 표 는 특수 합 니 다.일반적인 문자 표 순서 와 차이 가 있 습 니 다.
itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
//input 즉 hash,count=16
function encode64($input, $count)
{
$output = '';
$i = 0;
do
{
$value = ord($input[$i++]);// acsii
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
상기 방법 으로 22 비트 암호 화 된 비밀 번 호 를 얻 을 수 있 습 니 다.
4.C 로 wordpress 의 암호 화 실현
다음은 본인 이 C 로 구현 한 코드 입 니 다.오류 가 있 으 면 지적 해 주 십시오!
wordpress.c 파일:
#include <stdio.h>
#include <string.h>
#include "md5.h"
#include "wordpress.h"
#define WORDPRESS_MD5_CHAR_NUM 16
unsigned char base64Char[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
void md5_to_unsigned_char(unsigned char *hash)
{
int i;
unsigned char md5[17];
for (i = 0; i < 16; i++)
{
if (hash[2*i] >= '0' && hash[2*i] <= '9')
md5[i] = (hash[2*i] - '0') << 4;
else if (hash[2*i] >= 'a' && hash[2*i] <= 'f')
md5[i] = (hash[2*i] - 'a') <<4;
if (hash[2*i+1] >= '0' && hash[2*i+1] <= '9')
md5[i] = md5[i] | ((hash[2*i+1] - '0') & 0x0f);
else if (hash[2*i+1] >= 'a' && hash[2*i+1] <= 'f')
md5[i] = md5[i] | ((hash[2*i+1] - 'a') & 0x0f);
}
md5[16] = '\0';
for (i = 0; i < 16; i++)
hash[i] = md5[i];
hash[16] = '\0';
}
void base64Encode(unsigned char *md5, unsigned char *result)
{
int num_24bits = 5;
int i;
for (i = 0; i < num_24bits; ++i)
{
result[4 * i + 0] = base64Char[(md5[3 * i] >> 2) & 0x3F];
result[4 * i + 1] = base64Char[(((md5[3 * i] & 0x3) << 4) | (md5[3 * i + 1] >> 4)) & 0x3F];
result[4 * i + 2] = base64Char[((md5[3 * i + 1] << 2) | (md5[3 * i + 2] >> 6)) & 0x3F];
result[4 * i + 3] = base64Char[md5[3 * i + 2] & 0x3F];
}
result[20] = base64Char[md5[15] >> 2];
result[21] = base64Char[(md5[15] << 4) & 0x3F];
result[22] = '\0';
}
int wordpress( unsigned char * salt, unsigned char *passwd, int count, unsigned char *code )
{
int i, j;
char symbol;
unsigned char buffer[100];
unsigned char base64_code[23];
int len = strlen( (char *)passwd );
if (strlen( (char *)salt ) != 8)
{
printf("illegal salt!
");
return 1;
}
if (count != 8192 && count != 2048)
{
printf("illegal count!
");
return 1;
}
//first time use md5 function with salt
strcpy( (char *)buffer, (char *)salt );
strcat( (char *)buffer, (char *)passwd );
MD5( buffer, strlen( (char *)buffer), buffer, 0 );
md5_to_unsigned_char( buffer );
//count times md5 function
for (i = 0; i < count; i++)
{
memcpy( (void *)&buffer[WORDPRESS_MD5_CHAR_NUM], passwd, len );
MD5( buffer, WORDPRESS_MD5_CHAR_NUM + len, buffer, 0 );
md5_to_unsigned_char( buffer );
}
memcpy( (void *)code, buffer, 32);
base64Encode( buffer, base64_code );
if (count == 8192)
symbol = 'B';
else if(count == 2048)
symbol = '9';
strcpy( (char *)code, "$P$" );
code[3] = symbol;
code[4] = '\0';
strcat( (char *)code, (char *)salt);
memcpy( (void *)&code[12], base64_code, 22);
return 0;
}
이전에 자신 이 쓴 md5 코드 를 동봉 합 니 다:
#include "md5.h"
#include <stdio.h>
#include <memory.h>
#include <string.h>
#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x^y^z)
#define I(x,y,z) (y ^ (x | ~z))
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
#define FF(a,b,c,d,x,s,ac) \
{ \
a += F(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define GG(a,b,c,d,x,s,ac) \
{ \
a += G(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define HH(a,b,c,d,x,s,ac) \
{ \
a += H(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define II(a,b,c,d,x,s,ac) \
{ \
a += I(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
void MD5Init(MD5_CTX *context);
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);
void MD5Final(MD5_CTX *context,unsigned char digest[16]);
void MD5Transform(unsigned int state[4],unsigned char block[64]);
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len);
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len);
unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
void MD5Init(MD5_CTX *context)
{
context->count[0] = 0;
context->count[1] = 0;
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
}
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)
{
unsigned int i = 0,index = 0,partlen = 0;
index = (context->count[0] >> 3) & 0x3F;
partlen = 64 - index;
context->count[0] += inputlen << 3;
if(context->count[0] < (inputlen << 3))
context->count[1]++;
context->count[1] += inputlen >> 29;
if(inputlen >= partlen)
{
memcpy(&context->buffer[index],input,partlen);
MD5Transform(context->state,context->buffer);
for(i = partlen;i+64 <= inputlen;i+=64)
MD5Transform(context->state,&input[i]);
index = 0;
}
else
{
i = 0;
}
memcpy(&context->buffer[index],&input[i],inputlen-i);
}
void MD5Final(MD5_CTX *context,unsigned char digest[16])
{
unsigned int index = 0,padlen = 0;
unsigned char bits[8];
index = (context->count[0] >> 3) & 0x3F;
padlen = (index < 56)?(56-index):(120-index);
MD5Encode(bits,context->count,8);
MD5Update(context,PADDING,padlen);
MD5Update(context,bits,8);
MD5Encode(digest,context->state,16);
}
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[j] = input[i] & 0xFF;
output[j+1] = (input[i] >> 8) & 0xFF;
output[j+2] = (input[i] >> 16) & 0xFF;
output[j+3] = (input[i] >> 24) & 0xFF;
i++;
j+=4;
}
}
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[i] = (input[j]) |
(input[j+1] << 8) |
(input[j+2] << 16) |
(input[j+3] << 24);
i++;
j+=4;
}
}
void MD5Transform(unsigned int state[4],unsigned char block[64])
{
unsigned int a = state[0];
unsigned int b = state[1];
unsigned int c = state[2];
unsigned int d = state[3];
unsigned int x[64];
MD5Decode(x,block,64);
FF(a, b, c, d, x[ 0], 7, 0xd76aa478);
FF(d, a, b, c, x[ 1], 12, 0xe8c7b756);
FF(c, d, a, b, x[ 2], 17, 0x242070db);
FF(b, c, d, a, x[ 3], 22, 0xc1bdceee);
FF(a, b, c, d, x[ 4], 7, 0xf57c0faf);
FF(d, a, b, c, x[ 5], 12, 0x4787c62a);
FF(c, d, a, b, x[ 6], 17, 0xa8304613);
FF(b, c, d, a, x[ 7], 22, 0xfd469501);
FF(a, b, c, d, x[ 8], 7, 0x698098d8);
FF(d, a, b, c, x[ 9], 12, 0x8b44f7af);
FF(c, d, a, b, x[10], 17, 0xffff5bb1);
FF(b, c, d, a, x[11], 22, 0x895cd7be);
FF(a, b, c, d, x[12], 7, 0x6b901122);
FF(d, a, b, c, x[13], 12, 0xfd987193);
FF(c, d, a, b, x[14], 17, 0xa679438e);
FF(b, c, d, a, x[15], 22, 0x49b40821);
GG(a, b, c, d, x[ 1], 5, 0xf61e2562);
GG(d, a, b, c, x[ 6], 9, 0xc040b340);
GG(c, d, a, b, x[11], 14, 0x265e5a51);
GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa);
GG(a, b, c, d, x[ 5], 5, 0xd62f105d);
GG(d, a, b, c, x[10], 9, 0x2441453);
GG(c, d, a, b, x[15], 14, 0xd8a1e681);
GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8);
GG(a, b, c, d, x[ 9], 5, 0x21e1cde6);
GG(d, a, b, c, x[14], 9, 0xc33707d6);
GG(c, d, a, b, x[ 3], 14, 0xf4d50d87);
GG(b, c, d, a, x[ 8], 20, 0x455a14ed);
GG(a, b, c, d, x[13], 5, 0xa9e3e905);
GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8);
GG(c, d, a, b, x[ 7], 14, 0x676f02d9);
GG(b, c, d, a, x[12], 20, 0x8d2a4c8a);
HH(a, b, c, d, x[ 5], 4, 0xfffa3942);
HH(d, a, b, c, x[ 8], 11, 0x8771f681);
HH(c, d, a, b, x[11], 16, 0x6d9d6122);
HH(b, c, d, a, x[14], 23, 0xfde5380c);
HH(a, b, c, d, x[ 1], 4, 0xa4beea44);
HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9);
HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60);
HH(b, c, d, a, x[10], 23, 0xbebfbc70);
HH(a, b, c, d, x[13], 4, 0x289b7ec6);
HH(d, a, b, c, x[ 0], 11, 0xeaa127fa);
HH(c, d, a, b, x[ 3], 16, 0xd4ef3085);
HH(b, c, d, a, x[ 6], 23, 0x4881d05);
HH(a, b, c, d, x[ 9], 4, 0xd9d4d039);
HH(d, a, b, c, x[12], 11, 0xe6db99e5);
HH(c, d, a, b, x[15], 16, 0x1fa27cf8);
HH(b, c, d, a, x[ 2], 23, 0xc4ac5665);
II(a, b, c, d, x[ 0], 6, 0xf4292244);
II(d, a, b, c, x[ 7], 10, 0x432aff97);
II(c, d, a, b, x[14], 15, 0xab9423a7);
II(b, c, d, a, x[ 5], 21, 0xfc93a039);
II(a, b, c, d, x[12], 6, 0x655b59c3);
II(d, a, b, c, x[ 3], 10, 0x8f0ccc92);
II(c, d, a, b, x[10], 15, 0xffeff47d);
II(b, c, d, a, x[ 1], 21, 0x85845dd1);
II(a, b, c, d, x[ 8], 6, 0x6fa87e4f);
II(d, a, b, c, x[15], 10, 0xfe2ce6e0);
II(c, d, a, b, x[ 6], 15, 0xa3014314);
II(b, c, d, a, x[13], 21, 0x4e0811a1);
II(a, b, c, d, x[ 4], 6, 0xf7537e82);
II(d, a, b, c, x[11], 10, 0xbd3af235);
II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb);
II(b, c, d, a, x[ 9], 21, 0xeb86d391);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
void MD5(unsigned char * buf, unsigned int len, unsigned char *out, int type)
{
int i;
MD5_CTX md5;
unsigned char digest[16];
char hex[]="0123456789abcdef";
char HEX[]="0123456789ABCDEF";
MD5Init(&md5);
MD5Update(&md5, buf,len);
MD5Final(&md5, digest);
if (type == 0)
{
for (i = 0; i < 16; i++)
{
out[i+i] = hex[digest[i] >> 4];
out[i+i+1] = hex[digest[i] & 0x0f];
}
}
else if (type == 1)
{
for (i = 0; i < 16; i++)
{
out[i+i] = HEX[digest[i] >> 4];
out[i+i+1] = HEX[digest[i] & 0x0f];
}
}
out[i+i] = '\0';
}
테스트 코드:
#include <stdio.h>
#include "wordpress.h"
int main()
{
unsigned char passwd[] = "12345678";
unsigned char salt[] = "12345687";
unsigned char code[40];
wordpress(salt, passwd, 8192, code);
printf("code: %s
", code);
return 0;
}
[출처] https://intrepidgeeks.com/tutorial/part-1-analysis-of-wordpress-user-encryption-principle-and-algorithm
[php worldpress] [위 에]wordpress 사용자 암호 화 원리 및 알고리즘 분석
[설명]본 글 은 학습 교류 에 만 사용 되 며 상업 용도 로 사용 하지 마 십시오.현지 법 규 를 위반 하지 마 십시오.그렇지 않 으 면 결 과 는 스스로 책임 져 야 합 니 다.
전재 본 논문 의 출처 를 밝 혀 주 십시오.http://blog.csdn.net/hk_jh/article/details/27368279
1.워드 프레스 가 무엇 입 니까?
워드 프레스 에 대한 소 개 는 위 키 피 디 아 를 참조 하 시기 바 랍 니 다.http://zh.wikipedia.org/wiki/Wordpress
사실 암호 화 원 리 를 파악 하고 효율 적 인 언어 로 이 루어 지면 폭력 적 인 해결 이 쉽 지 않 겠 습 니까?
2.wordpress 사용자 암호 화 알고리즘
우선,워드 프레스 는 오픈 소스 입 니 다.홈 페이지 에서 소스 코드 를 다운로드 할 수 있 습 니 다.또한 wordpress 는 php 언어 로 작 성 된 것 입 니 다.
wordpress 사용자 암호 화 후의 암호 화 형식:
$P$BcSda3/tRXQcRZMPj3cUI0jZJFdMgL0 $P$BNclJc4wbM.vSjKPYxKggDPtw3siXQ0
다음은 압축 해제 후 폴 더/include 의 class-phopass.phop 파일 의 코드 입 니 다.주로 사용자 암 호 를 암호 화 하 는 클래스 와 함 수 를 포함 합 니 다.
<?php
/**
* Portable PHP password hashing framework.
* @package phpass
* @since 2.5.0
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
*/
#
# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
# the public domain. Revised in subsequent years, still public domain.
#
# There's absolutely no warranty.
#
# Please be sure to update the Version line if you edit this file in any way.
# It is suggested that you leave the main version number intact, but indicate
# your project name (after the slash) and add your own revision information.
#
# Please do not change the "private" password hashing method implemented in
# here, thereby making your hashes incompatible. However, if you must, please
# change the hash type identifier (the "$P$") to something different.
#
# Obviously, since this code is in the public domain, the above are not
# requirements (there can be none), but merely suggestions.
#
/**
* Portable PHP password hashing framework.
*
* @package phpass
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
* @since 2.5.0
*/
class PasswordHash {
var $itoa64;
var $iteration_count_log2;
var $portable_hashes;
var $random_state;
function PasswordHash($iteration_count_log2, $portable_hashes)
{
$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
$iteration_count_log2 = 8;
$this->iteration_count_log2 = $iteration_count_log2;
$this->portable_hashes = $portable_hashes;
$this->random_state = microtime() . uniqid(rand(), TRUE); // removed getmypid() for compatibility reasons
}
function get_random_bytes($count)
{
$output = '';
if ( @is_readable('/dev/urandom') &&
($fh = @fopen('/dev/urandom', 'rb'))) {
$output = fread($fh, $count);
fclose($fh);
}
if (strlen($output) < $count) {
$output = '';
for ($i = 0; $i < $count; $i += 16) {
$this->random_state =
md5(microtime() . $this->random_state);
$output .=
pack('H*', md5($this->random_state));
}
$output = substr($output, 0, $count);
}
return $output;
}
function encode64($input, $count)
{
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
function gensalt_private($input)
{
$output = '$P$';
$output .= $this->itoa64[min($this->iteration_count_log2 +
((PHP_VERSION >= '5') ? 5 : 3), 30)];
$output .= $this->encode64($input, 6);
return $output;
}
function crypt_private($password, $setting)
{
$output = '*0';
if (substr($setting, 0, 2) == $output)
$output = '*1';
$id = substr($setting, 0, 3);
# We use "$P$", phpBB3 uses "$H$" for the same thing
if ($id != '$P$' && $id != '$H$')
return $output;
$count_log2 = strpos($this->itoa64, $setting[3]);
if ($count_log2 < 7 || $count_log2 > 30)
return $output;
$count = 1 << $count_log2;
$salt = substr($setting, 4, 8);
if (strlen($salt) != 8)
return $output;
# We're kind of forced to use MD5 here since it's the only
# cryptographic primitive available in all versions of PHP
# currently in use. To implement our own low-level crypto
# in PHP would result in much worse performance and
# consequently in lower iteration counts and hashes that are
# quicker to crack (by non-PHP code).
if (PHP_VERSION >= '5') {
$hash = md5($salt . $password, TRUE);
do {
$hash = md5($hash . $password, TRUE);
} while (--$count);
} else {
$hash = pack('H*', md5($salt . $password));
do {
$hash = pack('H*', md5($hash . $password));
} while (--$count);
}
$output = substr($setting, 0, 12);
$output .= $this->encode64($hash, 16);
return $output;
}
function gensalt_extended($input)
{
$count_log2 = min($this->iteration_count_log2 + 8, 24);
# This should be odd to not reveal weak DES keys, and the
# maximum valid value is (2**24 - 1) which is odd anyway.
$count = (1 << $count_log2) - 1;
$output = '_';
$output .= $this->itoa64[$count & 0x3f];
$output .= $this->itoa64[($count >> 6) & 0x3f];
$output .= $this->itoa64[($count >> 12) & 0x3f];
$output .= $this->itoa64[($count >> 18) & 0x3f];
$output .= $this->encode64($input, 3);
return $output;
}
function gensalt_blowfish($input)
{
# This one needs to use a different order of characters and a
# different encoding scheme from the one in encode64() above.
# We care because the last character in our encoded string will
# only represent 2 bits. While two known implementations of
# bcrypt will happily accept and correct a salt string which
# has the 4 unused bits set to non-zero, we do not want to take
# chances and we also do not want to waste an additional byte
# of entropy.
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '$2a$';
$output .= chr(ord('0') + $this->iteration_count_log2 / 10);
$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
$output .= '$';
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (1);
return $output;
}
function HashPassword($password)
{
$random = '';
if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
$random = $this->get_random_bytes(16);
$hash =
crypt($password, $this->gensalt_blowfish($random));
if (strlen($hash) == 60)
return $hash;
}
if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
if (strlen($random) < 3)
$random = $this->get_random_bytes(3);
$hash =
crypt($password, $this->gensalt_extended($random));
if (strlen($hash) == 20)
return $hash;
}
if (strlen($random) < 6)
$random = $this->get_random_bytes(6);
$hash =
$this->crypt_private($password,
$this->gensalt_private($random));
if (strlen($hash) == 34)
return $hash;
# Returning '*' on error is safe here, but would _not_ be safe
# in a crypt(3)-like function used _both_ for generating new
# hashes and for validating passwords against existing hashes.
return '*';
}
function CheckPassword($password, $stored_hash)
{
$hash = $this->crypt_private($password, $stored_hash);
if ($hash[0] == '*')
$hash = crypt($password, $stored_hash);
return $hash === $stored_hash;
}
}
?>
3.알고리즘 분석
(1)wordpress 암호 화 된 비밀문서 형식:$P$B12345678huiyw4r7qhfuhs8yjmd6ef$P$912345678huiyw4r7qhfuhs8yjmd6ef 1 단:$P$형식 고정 2 단:한 글자 만 있 습 니 다.phop 버 전이 5.0 이상 이면 B 이 고 그렇지 않 으 면 9 세 번 째 단계 입 니 다.8 비트 salt 네 번 째 단계:22 비트,실제 암호 화 된 암호 화 방법 phop 버 전 은 5.0 보다 높 습 니 다.
$hash = md5($salt . $password, TRUE);
do
{
$hash = md5($hash . $password, TRUE);
} while (--$count);
[주]"."php 에서 연결 연산 입 니 다.
파라미터 TRUR 는 암호 화 결 과 를 16 바이트 바 이 너 리 로 표시 합 니 다.
count 2 의 13 차방:8192
php 버 전 5.0 이하
$hash = pack('H*', md5($salt . $password));
do
{
$hash = pack('H*', md5($hash . $password));
} while (--$count);
[주]phop 이 5.0 md5 보다 낮 으 면 32 비트 16 진수 문자열 형식 으로 돌아 갑 니 다.
pack(H*)은 md5 결 과 를 2 진법 으로 바꾼다.
count 취 2 의 11 차방:2048
상기 방법 으로 얻 은$hash 를 base 64 암호 화 합 니 다:
(3)wordpress 의 base 64 알고리즘
64 비트 문자 표 는 특수 합 니 다.일반적인 문자 표 순서 와 차이 가 있 습 니 다.
itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
//input 즉 hash,count=16
function encode64($input, $count)
{
$output = '';
$i = 0;
do
{
$value = ord($input[$i++]);// acsii
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
상기 방법 으로 22 비트 암호 화 된 비밀 번 호 를 얻 을 수 있 습 니 다.
4.C 로 wordpress 의 암호 화 실현
다음은 본인 이 C 로 구현 한 코드 입 니 다.오류 가 있 으 면 지적 해 주 십시오!
wordpress.c 파일:
#include <stdio.h>
#include <string.h>
#include "md5.h"
#include "wordpress.h"
#define WORDPRESS_MD5_CHAR_NUM 16
unsigned char base64Char[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
void md5_to_unsigned_char(unsigned char *hash)
{
int i;
unsigned char md5[17];
for (i = 0; i < 16; i++)
{
if (hash[2*i] >= '0' && hash[2*i] <= '9')
md5[i] = (hash[2*i] - '0') << 4;
else if (hash[2*i] >= 'a' && hash[2*i] <= 'f')
md5[i] = (hash[2*i] - 'a') <<4;
if (hash[2*i+1] >= '0' && hash[2*i+1] <= '9')
md5[i] = md5[i] | ((hash[2*i+1] - '0') & 0x0f);
else if (hash[2*i+1] >= 'a' && hash[2*i+1] <= 'f')
md5[i] = md5[i] | ((hash[2*i+1] - 'a') & 0x0f);
}
md5[16] = '\0';
for (i = 0; i < 16; i++)
hash[i] = md5[i];
hash[16] = '\0';
}
void base64Encode(unsigned char *md5, unsigned char *result)
{
int num_24bits = 5;
int i;
for (i = 0; i < num_24bits; ++i)
{
result[4 * i + 0] = base64Char[(md5[3 * i] >> 2) & 0x3F];
result[4 * i + 1] = base64Char[(((md5[3 * i] & 0x3) << 4) | (md5[3 * i + 1] >> 4)) & 0x3F];
result[4 * i + 2] = base64Char[((md5[3 * i + 1] << 2) | (md5[3 * i + 2] >> 6)) & 0x3F];
result[4 * i + 3] = base64Char[md5[3 * i + 2] & 0x3F];
}
result[20] = base64Char[md5[15] >> 2];
result[21] = base64Char[(md5[15] << 4) & 0x3F];
result[22] = '\0';
}
int wordpress( unsigned char * salt, unsigned char *passwd, int count, unsigned char *code )
{
int i, j;
char symbol;
unsigned char buffer[100];
unsigned char base64_code[23];
int len = strlen( (char *)passwd );
if (strlen( (char *)salt ) != 8)
{
printf("illegal salt!
");
return 1;
}
if (count != 8192 && count != 2048)
{
printf("illegal count!
");
return 1;
}
//first time use md5 function with salt
strcpy( (char *)buffer, (char *)salt );
strcat( (char *)buffer, (char *)passwd );
MD5( buffer, strlen( (char *)buffer), buffer, 0 );
md5_to_unsigned_char( buffer );
//count times md5 function
for (i = 0; i < count; i++)
{
memcpy( (void *)&buffer[WORDPRESS_MD5_CHAR_NUM], passwd, len );
MD5( buffer, WORDPRESS_MD5_CHAR_NUM + len, buffer, 0 );
md5_to_unsigned_char( buffer );
}
memcpy( (void *)code, buffer, 32);
base64Encode( buffer, base64_code );
if (count == 8192)
symbol = 'B';
else if(count == 2048)
symbol = '9';
strcpy( (char *)code, "$P$" );
code[3] = symbol;
code[4] = '\0';
strcat( (char *)code, (char *)salt);
memcpy( (void *)&code[12], base64_code, 22);
return 0;
}
이전에 자신 이 쓴 md5 코드 를 동봉 합 니 다:
#include "md5.h"
#include <stdio.h>
#include <memory.h>
#include <string.h>
#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x^y^z)
#define I(x,y,z) (y ^ (x | ~z))
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
#define FF(a,b,c,d,x,s,ac) \
{ \
a += F(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define GG(a,b,c,d,x,s,ac) \
{ \
a += G(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define HH(a,b,c,d,x,s,ac) \
{ \
a += H(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define II(a,b,c,d,x,s,ac) \
{ \
a += I(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
void MD5Init(MD5_CTX *context);
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);
void MD5Final(MD5_CTX *context,unsigned char digest[16]);
void MD5Transform(unsigned int state[4],unsigned char block[64]);
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len);
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len);
unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
void MD5Init(MD5_CTX *context)
{
context->count[0] = 0;
context->count[1] = 0;
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
}
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)
{
unsigned int i = 0,index = 0,partlen = 0;
index = (context->count[0] >> 3) & 0x3F;
partlen = 64 - index;
context->count[0] += inputlen << 3;
if(context->count[0] < (inputlen << 3))
context->count[1]++;
context->count[1] += inputlen >> 29;
if(inputlen >= partlen)
{
memcpy(&context->buffer[index],input,partlen);
MD5Transform(context->state,context->buffer);
for(i = partlen;i+64 <= inputlen;i+=64)
MD5Transform(context->state,&input[i]);
index = 0;
}
else
{
i = 0;
}
memcpy(&context->buffer[index],&input[i],inputlen-i);
}
void MD5Final(MD5_CTX *context,unsigned char digest[16])
{
unsigned int index = 0,padlen = 0;
unsigned char bits[8];
index = (context->count[0] >> 3) & 0x3F;
padlen = (index < 56)?(56-index):(120-index);
MD5Encode(bits,context->count,8);
MD5Update(context,PADDING,padlen);
MD5Update(context,bits,8);
MD5Encode(digest,context->state,16);
}
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[j] = input[i] & 0xFF;
output[j+1] = (input[i] >> 8) & 0xFF;
output[j+2] = (input[i] >> 16) & 0xFF;
output[j+3] = (input[i] >> 24) & 0xFF;
i++;
j+=4;
}
}
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[i] = (input[j]) |
(input[j+1] << 8) |
(input[j+2] << 16) |
(input[j+3] << 24);
i++;
j+=4;
}
}
void MD5Transform(unsigned int state[4],unsigned char block[64])
{
unsigned int a = state[0];
unsigned int b = state[1];
unsigned int c = state[2];
unsigned int d = state[3];
unsigned int x[64];
MD5Decode(x,block,64);
FF(a, b, c, d, x[ 0], 7, 0xd76aa478);
FF(d, a, b, c, x[ 1], 12, 0xe8c7b756);
FF(c, d, a, b, x[ 2], 17, 0x242070db);
FF(b, c, d, a, x[ 3], 22, 0xc1bdceee);
FF(a, b, c, d, x[ 4], 7, 0xf57c0faf);
FF(d, a, b, c, x[ 5], 12, 0x4787c62a);
FF(c, d, a, b, x[ 6], 17, 0xa8304613);
FF(b, c, d, a, x[ 7], 22, 0xfd469501);
FF(a, b, c, d, x[ 8], 7, 0x698098d8);
FF(d, a, b, c, x[ 9], 12, 0x8b44f7af);
FF(c, d, a, b, x[10], 17, 0xffff5bb1);
FF(b, c, d, a, x[11], 22, 0x895cd7be);
FF(a, b, c, d, x[12], 7, 0x6b901122);
FF(d, a, b, c, x[13], 12, 0xfd987193);
FF(c, d, a, b, x[14], 17, 0xa679438e);
FF(b, c, d, a, x[15], 22, 0x49b40821);
GG(a, b, c, d, x[ 1], 5, 0xf61e2562);
GG(d, a, b, c, x[ 6], 9, 0xc040b340);
GG(c, d, a, b, x[11], 14, 0x265e5a51);
GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa);
GG(a, b, c, d, x[ 5], 5, 0xd62f105d);
GG(d, a, b, c, x[10], 9, 0x2441453);
GG(c, d, a, b, x[15], 14, 0xd8a1e681);
GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8);
GG(a, b, c, d, x[ 9], 5, 0x21e1cde6);
GG(d, a, b, c, x[14], 9, 0xc33707d6);
GG(c, d, a, b, x[ 3], 14, 0xf4d50d87);
GG(b, c, d, a, x[ 8], 20, 0x455a14ed);
GG(a, b, c, d, x[13], 5, 0xa9e3e905);
GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8);
GG(c, d, a, b, x[ 7], 14, 0x676f02d9);
GG(b, c, d, a, x[12], 20, 0x8d2a4c8a);
HH(a, b, c, d, x[ 5], 4, 0xfffa3942);
HH(d, a, b, c, x[ 8], 11, 0x8771f681);
HH(c, d, a, b, x[11], 16, 0x6d9d6122);
HH(b, c, d, a, x[14], 23, 0xfde5380c);
HH(a, b, c, d, x[ 1], 4, 0xa4beea44);
HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9);
HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60);
HH(b, c, d, a, x[10], 23, 0xbebfbc70);
HH(a, b, c, d, x[13], 4, 0x289b7ec6);
HH(d, a, b, c, x[ 0], 11, 0xeaa127fa);
HH(c, d, a, b, x[ 3], 16, 0xd4ef3085);
HH(b, c, d, a, x[ 6], 23, 0x4881d05);
HH(a, b, c, d, x[ 9], 4, 0xd9d4d039);
HH(d, a, b, c, x[12], 11, 0xe6db99e5);
HH(c, d, a, b, x[15], 16, 0x1fa27cf8);
HH(b, c, d, a, x[ 2], 23, 0xc4ac5665);
II(a, b, c, d, x[ 0], 6, 0xf4292244);
II(d, a, b, c, x[ 7], 10, 0x432aff97);
II(c, d, a, b, x[14], 15, 0xab9423a7);
II(b, c, d, a, x[ 5], 21, 0xfc93a039);
II(a, b, c, d, x[12], 6, 0x655b59c3);
II(d, a, b, c, x[ 3], 10, 0x8f0ccc92);
II(c, d, a, b, x[10], 15, 0xffeff47d);
II(b, c, d, a, x[ 1], 21, 0x85845dd1);
II(a, b, c, d, x[ 8], 6, 0x6fa87e4f);
II(d, a, b, c, x[15], 10, 0xfe2ce6e0);
II(c, d, a, b, x[ 6], 15, 0xa3014314);
II(b, c, d, a, x[13], 21, 0x4e0811a1);
II(a, b, c, d, x[ 4], 6, 0xf7537e82);
II(d, a, b, c, x[11], 10, 0xbd3af235);
II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb);
II(b, c, d, a, x[ 9], 21, 0xeb86d391);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
void MD5(unsigned char * buf, unsigned int len, unsigned char *out, int type)
{
int i;
MD5_CTX md5;
unsigned char digest[16];
char hex[]="0123456789abcdef";
char HEX[]="0123456789ABCDEF";
MD5Init(&md5);
MD5Update(&md5, buf,len);
MD5Final(&md5, digest);
if (type == 0)
{
for (i = 0; i < 16; i++)
{
out[i+i] = hex[digest[i] >> 4];
out[i+i+1] = hex[digest[i] & 0x0f];
}
}
else if (type == 1)
{
for (i = 0; i < 16; i++)
{
out[i+i] = HEX[digest[i] >> 4];
out[i+i+1] = HEX[digest[i] & 0x0f];
}
}
out[i+i] = '\0';
}
테스트 코드:
#include <stdio.h>
#include "wordpress.h"
int main()
{
unsigned char passwd[] = "12345678";
unsigned char salt[] = "12345687";
unsigned char code[40];
wordpress(salt, passwd, 8192, code);
printf("code: %s
", code);
return 0;
}
[출처] https://intrepidgeeks.com/tutorial/part-1-analysis-of-wordpress-user-encryption-principle-and-algorithm
[php worldpress] [위 에]wordpress 사용자 암호 화 원리 및 알고리즘 분석
[설명]본 글 은 학습 교류 에 만 사용 되 며 상업 용도 로 사용 하지 마 십시오.현지 법 규 를 위반 하지 마 십시오.그렇지 않 으 면 결 과 는 스스로 책임 져 야 합 니 다.
전재 본 논문 의 출처 를 밝 혀 주 십시오.http://blog.csdn.net/hk_jh/article/details/27368279
1.워드 프레스 가 무엇 입 니까?
워드 프레스 에 대한 소 개 는 위 키 피 디 아 를 참조 하 시기 바 랍 니 다.http://zh.wikipedia.org/wiki/Wordpress
사실 암호 화 원 리 를 파악 하고 효율 적 인 언어 로 이 루어 지면 폭력 적 인 해결 이 쉽 지 않 겠 습 니까?
2.wordpress 사용자 암호 화 알고리즘
우선,워드 프레스 는 오픈 소스 입 니 다.홈 페이지 에서 소스 코드 를 다운로드 할 수 있 습 니 다.또한 wordpress 는 php 언어 로 작 성 된 것 입 니 다.
wordpress 사용자 암호 화 후의 암호 화 형식:
$P$BcSda3/tRXQcRZMPj3cUI0jZJFdMgL0 $P$BNclJc4wbM.vSjKPYxKggDPtw3siXQ0
다음은 압축 해제 후 폴 더/include 의 class-phopass.phop 파일 의 코드 입 니 다.주로 사용자 암 호 를 암호 화 하 는 클래스 와 함 수 를 포함 합 니 다.
<?php
/**
* Portable PHP password hashing framework.
* @package phpass
* @since 2.5.0
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
*/
#
# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
# the public domain. Revised in subsequent years, still public domain.
#
# There's absolutely no warranty.
#
# Please be sure to update the Version line if you edit this file in any way.
# It is suggested that you leave the main version number intact, but indicate
# your project name (after the slash) and add your own revision information.
#
# Please do not change the "private" password hashing method implemented in
# here, thereby making your hashes incompatible. However, if you must, please
# change the hash type identifier (the "$P$") to something different.
#
# Obviously, since this code is in the public domain, the above are not
# requirements (there can be none), but merely suggestions.
#
/**
* Portable PHP password hashing framework.
*
* @package phpass
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
* @since 2.5.0
*/
class PasswordHash {
var $itoa64;
var $iteration_count_log2;
var $portable_hashes;
var $random_state;
function PasswordHash($iteration_count_log2, $portable_hashes)
{
$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
$iteration_count_log2 = 8;
$this->iteration_count_log2 = $iteration_count_log2;
$this->portable_hashes = $portable_hashes;
$this->random_state = microtime() . uniqid(rand(), TRUE); // removed getmypid() for compatibility reasons
}
function get_random_bytes($count)
{
$output = '';
if ( @is_readable('/dev/urandom') &&
($fh = @fopen('/dev/urandom', 'rb'))) {
$output = fread($fh, $count);
fclose($fh);
}
if (strlen($output) < $count) {
$output = '';
for ($i = 0; $i < $count; $i += 16) {
$this->random_state =
md5(microtime() . $this->random_state);
$output .=
pack('H*', md5($this->random_state));
}
$output = substr($output, 0, $count);
}
return $output;
}
function encode64($input, $count)
{
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
function gensalt_private($input)
{
$output = '$P$';
$output .= $this->itoa64[min($this->iteration_count_log2 +
((PHP_VERSION >= '5') ? 5 : 3), 30)];
$output .= $this->encode64($input, 6);
return $output;
}
function crypt_private($password, $setting)
{
$output = '*0';
if (substr($setting, 0, 2) == $output)
$output = '*1';
$id = substr($setting, 0, 3);
# We use "$P$", phpBB3 uses "$H$" for the same thing
if ($id != '$P$' && $id != '$H$')
return $output;
$count_log2 = strpos($this->itoa64, $setting[3]);
if ($count_log2 < 7 || $count_log2 > 30)
return $output;
$count = 1 << $count_log2;
$salt = substr($setting, 4, 8);
if (strlen($salt) != 8)
return $output;
# We're kind of forced to use MD5 here since it's the only
# cryptographic primitive available in all versions of PHP
# currently in use. To implement our own low-level crypto
# in PHP would result in much worse performance and
# consequently in lower iteration counts and hashes that are
# quicker to crack (by non-PHP code).
if (PHP_VERSION >= '5') {
$hash = md5($salt . $password, TRUE);
do {
$hash = md5($hash . $password, TRUE);
} while (--$count);
} else {
$hash = pack('H*', md5($salt . $password));
do {
$hash = pack('H*', md5($hash . $password));
} while (--$count);
}
$output = substr($setting, 0, 12);
$output .= $this->encode64($hash, 16);
return $output;
}
function gensalt_extended($input)
{
$count_log2 = min($this->iteration_count_log2 + 8, 24);
# This should be odd to not reveal weak DES keys, and the
# maximum valid value is (2**24 - 1) which is odd anyway.
$count = (1 << $count_log2) - 1;
$output = '_';
$output .= $this->itoa64[$count & 0x3f];
$output .= $this->itoa64[($count >> 6) & 0x3f];
$output .= $this->itoa64[($count >> 12) & 0x3f];
$output .= $this->itoa64[($count >> 18) & 0x3f];
$output .= $this->encode64($input, 3);
return $output;
}
function gensalt_blowfish($input)
{
# This one needs to use a different order of characters and a
# different encoding scheme from the one in encode64() above.
# We care because the last character in our encoded string will
# only represent 2 bits. While two known implementations of
# bcrypt will happily accept and correct a salt string which
# has the 4 unused bits set to non-zero, we do not want to take
# chances and we also do not want to waste an additional byte
# of entropy.
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '$2a$';
$output .= chr(ord('0') + $this->iteration_count_log2 / 10);
$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
$output .= '$';
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (1);
return $output;
}
function HashPassword($password)
{
$random = '';
if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
$random = $this->get_random_bytes(16);
$hash =
crypt($password, $this->gensalt_blowfish($random));
if (strlen($hash) == 60)
return $hash;
}
if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
if (strlen($random) < 3)
$random = $this->get_random_bytes(3);
$hash =
crypt($password, $this->gensalt_extended($random));
if (strlen($hash) == 20)
return $hash;
}
if (strlen($random) < 6)
$random = $this->get_random_bytes(6);
$hash =
$this->crypt_private($password,
$this->gensalt_private($random));
if (strlen($hash) == 34)
return $hash;
# Returning '*' on error is safe here, but would _not_ be safe
# in a crypt(3)-like function used _both_ for generating new
# hashes and for validating passwords against existing hashes.
return '*';
}
function CheckPassword($password, $stored_hash)
{
$hash = $this->crypt_private($password, $stored_hash);
if ($hash[0] == '*')
$hash = crypt($password, $stored_hash);
return $hash === $stored_hash;
}
}
?>
3.알고리즘 분석
(1)wordpress 암호 화 된 비밀문서 형식:$P$B12345678huiyw4r7qhfuhs8yjmd6ef$P$912345678huiyw4r7qhfuhs8yjmd6ef 1 단:$P$형식 고정 2 단:한 글자 만 있 습 니 다.phop 버 전이 5.0 이상 이면 B 이 고 그렇지 않 으 면 9 세 번 째 단계 입 니 다.8 비트 salt 네 번 째 단계:22 비트,실제 암호 화 된 암호 화 방법 phop 버 전 은 5.0 보다 높 습 니 다.
$hash = md5($salt . $password, TRUE);
do
{
$hash = md5($hash . $password, TRUE);
} while (--$count);
[주]"."php 에서 연결 연산 입 니 다.
파라미터 TRUR 는 암호 화 결 과 를 16 바이트 바 이 너 리 로 표시 합 니 다.
count 2 의 13 차방:8192
php 버 전 5.0 이하
$hash = pack('H*', md5($salt . $password));
do
{
$hash = pack('H*', md5($hash . $password));
} while (--$count);
[주]phop 이 5.0 md5 보다 낮 으 면 32 비트 16 진수 문자열 형식 으로 돌아 갑 니 다.
pack(H*)은 md5 결 과 를 2 진법 으로 바꾼다.
count 취 2 의 11 차방:2048
상기 방법 으로 얻 은$hash 를 base 64 암호 화 합 니 다:
(3)wordpress 의 base 64 알고리즘
64 비트 문자 표 는 특수 합 니 다.일반적인 문자 표 순서 와 차이 가 있 습 니 다.
itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
//input 즉 hash,count=16
function encode64($input, $count)
{
$output = '';
$i = 0;
do
{
$value = ord($input[$i++]);// acsii
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
상기 방법 으로 22 비트 암호 화 된 비밀 번 호 를 얻 을 수 있 습 니 다.
4.C 로 wordpress 의 암호 화 실현
다음은 본인 이 C 로 구현 한 코드 입 니 다.오류 가 있 으 면 지적 해 주 십시오!
wordpress.c 파일:
#include <stdio.h>
#include <string.h>
#include "md5.h"
#include "wordpress.h"
#define WORDPRESS_MD5_CHAR_NUM 16
unsigned char base64Char[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
void md5_to_unsigned_char(unsigned char *hash)
{
int i;
unsigned char md5[17];
for (i = 0; i < 16; i++)
{
if (hash[2*i] >= '0' && hash[2*i] <= '9')
md5[i] = (hash[2*i] - '0') << 4;
else if (hash[2*i] >= 'a' && hash[2*i] <= 'f')
md5[i] = (hash[2*i] - 'a') <<4;
if (hash[2*i+1] >= '0' && hash[2*i+1] <= '9')
md5[i] = md5[i] | ((hash[2*i+1] - '0') & 0x0f);
else if (hash[2*i+1] >= 'a' && hash[2*i+1] <= 'f')
md5[i] = md5[i] | ((hash[2*i+1] - 'a') & 0x0f);
}
md5[16] = '\0';
for (i = 0; i < 16; i++)
hash[i] = md5[i];
hash[16] = '\0';
}
void base64Encode(unsigned char *md5, unsigned char *result)
{
int num_24bits = 5;
int i;
for (i = 0; i < num_24bits; ++i)
{
result[4 * i + 0] = base64Char[(md5[3 * i] >> 2) & 0x3F];
result[4 * i + 1] = base64Char[(((md5[3 * i] & 0x3) << 4) | (md5[3 * i + 1] >> 4)) & 0x3F];
result[4 * i + 2] = base64Char[((md5[3 * i + 1] << 2) | (md5[3 * i + 2] >> 6)) & 0x3F];
result[4 * i + 3] = base64Char[md5[3 * i + 2] & 0x3F];
}
result[20] = base64Char[md5[15] >> 2];
result[21] = base64Char[(md5[15] << 4) & 0x3F];
result[22] = '\0';
}
int wordpress( unsigned char * salt, unsigned char *passwd, int count, unsigned char *code )
{
int i, j;
char symbol;
unsigned char buffer[100];
unsigned char base64_code[23];
int len = strlen( (char *)passwd );
if (strlen( (char *)salt ) != 8)
{
printf("illegal salt!
");
return 1;
}
if (count != 8192 && count != 2048)
{
printf("illegal count!
");
return 1;
}
//first time use md5 function with salt
strcpy( (char *)buffer, (char *)salt );
strcat( (char *)buffer, (char *)passwd );
MD5( buffer, strlen( (char *)buffer), buffer, 0 );
md5_to_unsigned_char( buffer );
//count times md5 function
for (i = 0; i < count; i++)
{
memcpy( (void *)&buffer[WORDPRESS_MD5_CHAR_NUM], passwd, len );
MD5( buffer, WORDPRESS_MD5_CHAR_NUM + len, buffer, 0 );
md5_to_unsigned_char( buffer );
}
memcpy( (void *)code, buffer, 32);
base64Encode( buffer, base64_code );
if (count == 8192)
symbol = 'B';
else if(count == 2048)
symbol = '9';
strcpy( (char *)code, "$P$" );
code[3] = symbol;
code[4] = '\0';
strcat( (char *)code, (char *)salt);
memcpy( (void *)&code[12], base64_code, 22);
return 0;
}
이전에 자신 이 쓴 md5 코드 를 동봉 합 니 다:
#include "md5.h"
#include <stdio.h>
#include <memory.h>
#include <string.h>
#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x^y^z)
#define I(x,y,z) (y ^ (x | ~z))
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
#define FF(a,b,c,d,x,s,ac) \
{ \
a += F(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define GG(a,b,c,d,x,s,ac) \
{ \
a += G(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define HH(a,b,c,d,x,s,ac) \
{ \
a += H(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define II(a,b,c,d,x,s,ac) \
{ \
a += I(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
void MD5Init(MD5_CTX *context);
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);
void MD5Final(MD5_CTX *context,unsigned char digest[16]);
void MD5Transform(unsigned int state[4],unsigned char block[64]);
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len);
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len);
unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
void MD5Init(MD5_CTX *context)
{
context->count[0] = 0;
context->count[1] = 0;
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
}
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)
{
unsigned int i = 0,index = 0,partlen = 0;
index = (context->count[0] >> 3) & 0x3F;
partlen = 64 - index;
context->count[0] += inputlen << 3;
if(context->count[0] < (inputlen << 3))
context->count[1]++;
context->count[1] += inputlen >> 29;
if(inputlen >= partlen)
{
memcpy(&context->buffer[index],input,partlen);
MD5Transform(context->state,context->buffer);
for(i = partlen;i+64 <= inputlen;i+=64)
MD5Transform(context->state,&input[i]);
index = 0;
}
else
{
i = 0;
}
memcpy(&context->buffer[index],&input[i],inputlen-i);
}
void MD5Final(MD5_CTX *context,unsigned char digest[16])
{
unsigned int index = 0,padlen = 0;
unsigned char bits[8];
index = (context->count[0] >> 3) & 0x3F;
padlen = (index < 56)?(56-index):(120-index);
MD5Encode(bits,context->count,8);
MD5Update(context,PADDING,padlen);
MD5Update(context,bits,8);
MD5Encode(digest,context->state,16);
}
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[j] = input[i] & 0xFF;
output[j+1] = (input[i] >> 8) & 0xFF;
output[j+2] = (input[i] >> 16) & 0xFF;
output[j+3] = (input[i] >> 24) & 0xFF;
i++;
j+=4;
}
}
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[i] = (input[j]) |
(input[j+1] << 8) |
(input[j+2] << 16) |
(input[j+3] << 24);
i++;
j+=4;
}
}
void MD5Transform(unsigned int state[4],unsigned char block[64])
{
unsigned int a = state[0];
unsigned int b = state[1];
unsigned int c = state[2];
unsigned int d = state[3];
unsigned int x[64];
MD5Decode(x,block,64);
FF(a, b, c, d, x[ 0], 7, 0xd76aa478);
FF(d, a, b, c, x[ 1], 12, 0xe8c7b756);
FF(c, d, a, b, x[ 2], 17, 0x242070db);
FF(b, c, d, a, x[ 3], 22, 0xc1bdceee);
FF(a, b, c, d, x[ 4], 7, 0xf57c0faf);
FF(d, a, b, c, x[ 5], 12, 0x4787c62a);
FF(c, d, a, b, x[ 6], 17, 0xa8304613);
FF(b, c, d, a, x[ 7], 22, 0xfd469501);
FF(a, b, c, d, x[ 8], 7, 0x698098d8);
FF(d, a, b, c, x[ 9], 12, 0x8b44f7af);
FF(c, d, a, b, x[10], 17, 0xffff5bb1);
FF(b, c, d, a, x[11], 22, 0x895cd7be);
FF(a, b, c, d, x[12], 7, 0x6b901122);
FF(d, a, b, c, x[13], 12, 0xfd987193);
FF(c, d, a, b, x[14], 17, 0xa679438e);
FF(b, c, d, a, x[15], 22, 0x49b40821);
GG(a, b, c, d, x[ 1], 5, 0xf61e2562);
GG(d, a, b, c, x[ 6], 9, 0xc040b340);
GG(c, d, a, b, x[11], 14, 0x265e5a51);
GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa);
GG(a, b, c, d, x[ 5], 5, 0xd62f105d);
GG(d, a, b, c, x[10], 9, 0x2441453);
GG(c, d, a, b, x[15], 14, 0xd8a1e681);
GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8);
GG(a, b, c, d, x[ 9], 5, 0x21e1cde6);
GG(d, a, b, c, x[14], 9, 0xc33707d6);
GG(c, d, a, b, x[ 3], 14, 0xf4d50d87);
GG(b, c, d, a, x[ 8], 20, 0x455a14ed);
GG(a, b, c, d, x[13], 5, 0xa9e3e905);
GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8);
GG(c, d, a, b, x[ 7], 14, 0x676f02d9);
GG(b, c, d, a, x[12], 20, 0x8d2a4c8a);
HH(a, b, c, d, x[ 5], 4, 0xfffa3942);
HH(d, a, b, c, x[ 8], 11, 0x8771f681);
HH(c, d, a, b, x[11], 16, 0x6d9d6122);
HH(b, c, d, a, x[14], 23, 0xfde5380c);
HH(a, b, c, d, x[ 1], 4, 0xa4beea44);
HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9);
HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60);
HH(b, c, d, a, x[10], 23, 0xbebfbc70);
HH(a, b, c, d, x[13], 4, 0x289b7ec6);
HH(d, a, b, c, x[ 0], 11, 0xeaa127fa);
HH(c, d, a, b, x[ 3], 16, 0xd4ef3085);
HH(b, c, d, a, x[ 6], 23, 0x4881d05);
HH(a, b, c, d, x[ 9], 4, 0xd9d4d039);
HH(d, a, b, c, x[12], 11, 0xe6db99e5);
HH(c, d, a, b, x[15], 16, 0x1fa27cf8);
HH(b, c, d, a, x[ 2], 23, 0xc4ac5665);
II(a, b, c, d, x[ 0], 6, 0xf4292244);
II(d, a, b, c, x[ 7], 10, 0x432aff97);
II(c, d, a, b, x[14], 15, 0xab9423a7);
II(b, c, d, a, x[ 5], 21, 0xfc93a039);
II(a, b, c, d, x[12], 6, 0x655b59c3);
II(d, a, b, c, x[ 3], 10, 0x8f0ccc92);
II(c, d, a, b, x[10], 15, 0xffeff47d);
II(b, c, d, a, x[ 1], 21, 0x85845dd1);
II(a, b, c, d, x[ 8], 6, 0x6fa87e4f);
II(d, a, b, c, x[15], 10, 0xfe2ce6e0);
II(c, d, a, b, x[ 6], 15, 0xa3014314);
II(b, c, d, a, x[13], 21, 0x4e0811a1);
II(a, b, c, d, x[ 4], 6, 0xf7537e82);
II(d, a, b, c, x[11], 10, 0xbd3af235);
II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb);
II(b, c, d, a, x[ 9], 21, 0xeb86d391);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
void MD5(unsigned char * buf, unsigned int len, unsigned char *out, int type)
{
int i;
MD5_CTX md5;
unsigned char digest[16];
char hex[]="0123456789abcdef";
char HEX[]="0123456789ABCDEF";
MD5Init(&md5);
MD5Update(&md5, buf,len);
MD5Final(&md5, digest);
if (type == 0)
{
for (i = 0; i < 16; i++)
{
out[i+i] = hex[digest[i] >> 4];
out[i+i+1] = hex[digest[i] & 0x0f];
}
}
else if (type == 1)
{
for (i = 0; i < 16; i++)
{
out[i+i] = HEX[digest[i] >> 4];
out[i+i+1] = HEX[digest[i] & 0x0f];
}
}
out[i+i] = '\0';
}
테스트 코드:
#include <stdio.h>
#include "wordpress.h"
int main()
{
unsigned char passwd[] = "12345678";
unsigned char salt[] = "12345687";
unsigned char code[40];
wordpress(salt, passwd, 8192, code);
printf("code: %s
", code);
return 0;
}
[출처] https://intrepidgeeks.com/tutorial/part-1-analysis-of-wordpress-user-encryption-principle-and-algorithm
이전에 자신 이 쓴 md5 코드 를 동봉 합 니 다:
#include "md5.h"
#include <stdio.h>
#include <memory.h>
#include <string.h>
#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x^y^z)
#define I(x,y,z) (y ^ (x | ~z))
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
#define FF(a,b,c,d,x,s,ac) \
{ \
a += F(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define GG(a,b,c,d,x,s,ac) \
{ \
a += G(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define HH(a,b,c,d,x,s,ac) \
{ \
a += H(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define II(a,b,c,d,x,s,ac) \
{ \
a += I(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
void MD5Init(MD5_CTX *context);
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);
void MD5Final(MD5_CTX *context,unsigned char digest[16]);
void MD5Transform(unsigned int state[4],unsigned char block[64]);
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len);
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len);
unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
void MD5Init(MD5_CTX *context)
{
context->count[0] = 0;
context->count[1] = 0;
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
}
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)
{
unsigned int i = 0,index = 0,partlen = 0;
index = (context->count[0] >> 3) & 0x3F;
partlen = 64 - index;
context->count[0] += inputlen << 3;
if(context->count[0] < (inputlen << 3))
context->count[1]++;
context->count[1] += inputlen >> 29;
if(inputlen >= partlen)
{
memcpy(&context->buffer[index],input,partlen);
MD5Transform(context->state,context->buffer);
for(i = partlen;i+64 <= inputlen;i+=64)
MD5Transform(context->state,&input[i]);
index = 0;
}
else
{
i = 0;
}
memcpy(&context->buffer[index],&input[i],inputlen-i);
}
void MD5Final(MD5_CTX *context,unsigned char digest[16])
{
unsigned int index = 0,padlen = 0;
unsigned char bits[8];
index = (context->count[0] >> 3) & 0x3F;
padlen = (index < 56)?(56-index):(120-index);
MD5Encode(bits,context->count,8);
MD5Update(context,PADDING,padlen);
MD5Update(context,bits,8);
MD5Encode(digest,context->state,16);
}
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[j] = input[i] & 0xFF;
output[j+1] = (input[i] >> 8) & 0xFF;
output[j+2] = (input[i] >> 16) & 0xFF;
output[j+3] = (input[i] >> 24) & 0xFF;
i++;
j+=4;
}
}
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[i] = (input[j]) |
(input[j+1] << 8) |
(input[j+2] << 16) |
(input[j+3] << 24);
i++;
j+=4;
}
}
void MD5Transform(unsigned int state[4],unsigned char block[64])
{
unsigned int a = state[0];
unsigned int b = state[1];
unsigned int c = state[2];
unsigned int d = state[3];
unsigned int x[64];
MD5Decode(x,block,64);
FF(a, b, c, d, x[ 0], 7, 0xd76aa478);
FF(d, a, b, c, x[ 1], 12, 0xe8c7b756);
FF(c, d, a, b, x[ 2], 17, 0x242070db);
FF(b, c, d, a, x[ 3], 22, 0xc1bdceee);
FF(a, b, c, d, x[ 4], 7, 0xf57c0faf);
FF(d, a, b, c, x[ 5], 12, 0x4787c62a);
FF(c, d, a, b, x[ 6], 17, 0xa8304613);
FF(b, c, d, a, x[ 7], 22, 0xfd469501);
FF(a, b, c, d, x[ 8], 7, 0x698098d8);
FF(d, a, b, c, x[ 9], 12, 0x8b44f7af);
FF(c, d, a, b, x[10], 17, 0xffff5bb1);
FF(b, c, d, a, x[11], 22, 0x895cd7be);
FF(a, b, c, d, x[12], 7, 0x6b901122);
FF(d, a, b, c, x[13], 12, 0xfd987193);
FF(c, d, a, b, x[14], 17, 0xa679438e);
FF(b, c, d, a, x[15], 22, 0x49b40821);
GG(a, b, c, d, x[ 1], 5, 0xf61e2562);
GG(d, a, b, c, x[ 6], 9, 0xc040b340);
GG(c, d, a, b, x[11], 14, 0x265e5a51);
GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa);
GG(a, b, c, d, x[ 5], 5, 0xd62f105d);
GG(d, a, b, c, x[10], 9, 0x2441453);
GG(c, d, a, b, x[15], 14, 0xd8a1e681);
GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8);
GG(a, b, c, d, x[ 9], 5, 0x21e1cde6);
GG(d, a, b, c, x[14], 9, 0xc33707d6);
GG(c, d, a, b, x[ 3], 14, 0xf4d50d87);
GG(b, c, d, a, x[ 8], 20, 0x455a14ed);
GG(a, b, c, d, x[13], 5, 0xa9e3e905);
GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8);
GG(c, d, a, b, x[ 7], 14, 0x676f02d9);
GG(b, c, d, a, x[12], 20, 0x8d2a4c8a);
HH(a, b, c, d, x[ 5], 4, 0xfffa3942);
HH(d, a, b, c, x[ 8], 11, 0x8771f681);
HH(c, d, a, b, x[11], 16, 0x6d9d6122);
HH(b, c, d, a, x[14], 23, 0xfde5380c);
HH(a, b, c, d, x[ 1], 4, 0xa4beea44);
HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9);
HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60);
HH(b, c, d, a, x[10], 23, 0xbebfbc70);
HH(a, b, c, d, x[13], 4, 0x289b7ec6);
HH(d, a, b, c, x[ 0], 11, 0xeaa127fa);
HH(c, d, a, b, x[ 3], 16, 0xd4ef3085);
HH(b, c, d, a, x[ 6], 23, 0x4881d05);
HH(a, b, c, d, x[ 9], 4, 0xd9d4d039);
HH(d, a, b, c, x[12], 11, 0xe6db99e5);
HH(c, d, a, b, x[15], 16, 0x1fa27cf8);
HH(b, c, d, a, x[ 2], 23, 0xc4ac5665);
II(a, b, c, d, x[ 0], 6, 0xf4292244);
II(d, a, b, c, x[ 7], 10, 0x432aff97);
II(c, d, a, b, x[14], 15, 0xab9423a7);
II(b, c, d, a, x[ 5], 21, 0xfc93a039);
II(a, b, c, d, x[12], 6, 0x655b59c3);
II(d, a, b, c, x[ 3], 10, 0x8f0ccc92);
II(c, d, a, b, x[10], 15, 0xffeff47d);
II(b, c, d, a, x[ 1], 21, 0x85845dd1);
II(a, b, c, d, x[ 8], 6, 0x6fa87e4f);
II(d, a, b, c, x[15], 10, 0xfe2ce6e0);
II(c, d, a, b, x[ 6], 15, 0xa3014314);
II(b, c, d, a, x[13], 21, 0x4e0811a1);
II(a, b, c, d, x[ 4], 6, 0xf7537e82);
II(d, a, b, c, x[11], 10, 0xbd3af235);
II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb);
II(b, c, d, a, x[ 9], 21, 0xeb86d391);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
void MD5(unsigned char * buf, unsigned int len, unsigned char *out, int type)
{
int i;
MD5_CTX md5;
unsigned char digest[16];
char hex[]="0123456789abcdef";
char HEX[]="0123456789ABCDEF";
MD5Init(&md5);
MD5Update(&md5, buf,len);
MD5Final(&md5, digest);
if (type == 0)
{
for (i = 0; i < 16; i++)
{
out[i+i] = hex[digest[i] >> 4];
out[i+i+1] = hex[digest[i] & 0x0f];
}
}
else if (type == 1)
{
for (i = 0; i < 16; i++)
{
out[i+i] = HEX[digest[i] >> 4];
out[i+i+1] = HEX[digest[i] & 0x0f];
}
}
out[i+i] = '[php worldpress] [위 에]wordpress 사용자 암호 화 원리 및 알고리즘 분석
[설명]본 글 은 학습 교류 에 만 사용 되 며 상업 용도 로 사용 하지 마 십시오.현지 법 규 를 위반 하지 마 십시오.그렇지 않 으 면 결 과 는 스스로 책임 져 야 합 니 다.
전재 본 논문 의 출처 를 밝 혀 주 십시오.http://blog.csdn.net/hk_jh/article/details/27368279
1.워드 프레스 가 무엇 입 니까?
워드 프레스 에 대한 소 개 는 위 키 피 디 아 를 참조 하 시기 바 랍 니 다.http://zh.wikipedia.org/wiki/Wordpress
사실 암호 화 원 리 를 파악 하고 효율 적 인 언어 로 이 루어 지면 폭력 적 인 해결 이 쉽 지 않 겠 습 니까?
2.wordpress 사용자 암호 화 알고리즘
우선,워드 프레스 는 오픈 소스 입 니 다.홈 페이지 에서 소스 코드 를 다운로드 할 수 있 습 니 다.또한 wordpress 는 php 언어 로 작 성 된 것 입 니 다.
wordpress 사용자 암호 화 후의 암호 화 형식:
$P$BcSda3/tRXQcRZMPj3cUI0jZJFdMgL0 $P$BNclJc4wbM.vSjKPYxKggDPtw3siXQ0
다음은 압축 해제 후 폴 더/include 의 class-phopass.phop 파일 의 코드 입 니 다.주로 사용자 암 호 를 암호 화 하 는 클래스 와 함 수 를 포함 합 니 다.
<?php
/**
* Portable PHP password hashing framework.
* @package phpass
* @since 2.5.0
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
*/
#
# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
# the public domain. Revised in subsequent years, still public domain.
#
# There's absolutely no warranty.
#
# Please be sure to update the Version line if you edit this file in any way.
# It is suggested that you leave the main version number intact, but indicate
# your project name (after the slash) and add your own revision information.
#
# Please do not change the "private" password hashing method implemented in
# here, thereby making your hashes incompatible. However, if you must, please
# change the hash type identifier (the "$P$") to something different.
#
# Obviously, since this code is in the public domain, the above are not
# requirements (there can be none), but merely suggestions.
#
/**
* Portable PHP password hashing framework.
*
* @package phpass
* @version 0.3 / WordPress
* @link http://www.openwall.com/phpass/
* @since 2.5.0
*/
class PasswordHash {
var $itoa64;
var $iteration_count_log2;
var $portable_hashes;
var $random_state;
function PasswordHash($iteration_count_log2, $portable_hashes)
{
$this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
$iteration_count_log2 = 8;
$this->iteration_count_log2 = $iteration_count_log2;
$this->portable_hashes = $portable_hashes;
$this->random_state = microtime() . uniqid(rand(), TRUE); // removed getmypid() for compatibility reasons
}
function get_random_bytes($count)
{
$output = '';
if ( @is_readable('/dev/urandom') &&
($fh = @fopen('/dev/urandom', 'rb'))) {
$output = fread($fh, $count);
fclose($fh);
}
if (strlen($output) < $count) {
$output = '';
for ($i = 0; $i < $count; $i += 16) {
$this->random_state =
md5(microtime() . $this->random_state);
$output .=
pack('H*', md5($this->random_state));
}
$output = substr($output, 0, $count);
}
return $output;
}
function encode64($input, $count)
{
$output = '';
$i = 0;
do {
$value = ord($input[$i++]);
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
function gensalt_private($input)
{
$output = '$P$';
$output .= $this->itoa64[min($this->iteration_count_log2 +
((PHP_VERSION >= '5') ? 5 : 3), 30)];
$output .= $this->encode64($input, 6);
return $output;
}
function crypt_private($password, $setting)
{
$output = '*0';
if (substr($setting, 0, 2) == $output)
$output = '*1';
$id = substr($setting, 0, 3);
# We use "$P$", phpBB3 uses "$H$" for the same thing
if ($id != '$P$' && $id != '$H$')
return $output;
$count_log2 = strpos($this->itoa64, $setting[3]);
if ($count_log2 < 7 || $count_log2 > 30)
return $output;
$count = 1 << $count_log2;
$salt = substr($setting, 4, 8);
if (strlen($salt) != 8)
return $output;
# We're kind of forced to use MD5 here since it's the only
# cryptographic primitive available in all versions of PHP
# currently in use. To implement our own low-level crypto
# in PHP would result in much worse performance and
# consequently in lower iteration counts and hashes that are
# quicker to crack (by non-PHP code).
if (PHP_VERSION >= '5') {
$hash = md5($salt . $password, TRUE);
do {
$hash = md5($hash . $password, TRUE);
} while (--$count);
} else {
$hash = pack('H*', md5($salt . $password));
do {
$hash = pack('H*', md5($hash . $password));
} while (--$count);
}
$output = substr($setting, 0, 12);
$output .= $this->encode64($hash, 16);
return $output;
}
function gensalt_extended($input)
{
$count_log2 = min($this->iteration_count_log2 + 8, 24);
# This should be odd to not reveal weak DES keys, and the
# maximum valid value is (2**24 - 1) which is odd anyway.
$count = (1 << $count_log2) - 1;
$output = '_';
$output .= $this->itoa64[$count & 0x3f];
$output .= $this->itoa64[($count >> 6) & 0x3f];
$output .= $this->itoa64[($count >> 12) & 0x3f];
$output .= $this->itoa64[($count >> 18) & 0x3f];
$output .= $this->encode64($input, 3);
return $output;
}
function gensalt_blowfish($input)
{
# This one needs to use a different order of characters and a
# different encoding scheme from the one in encode64() above.
# We care because the last character in our encoded string will
# only represent 2 bits. While two known implementations of
# bcrypt will happily accept and correct a salt string which
# has the 4 unused bits set to non-zero, we do not want to take
# chances and we also do not want to waste an additional byte
# of entropy.
$itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$output = '$2a$';
$output .= chr(ord('0') + $this->iteration_count_log2 / 10);
$output .= chr(ord('0') + $this->iteration_count_log2 % 10);
$output .= '$';
$i = 0;
do {
$c1 = ord($input[$i++]);
$output .= $itoa64[$c1 >> 2];
$c1 = ($c1 & 0x03) << 4;
if ($i >= 16) {
$output .= $itoa64[$c1];
break;
}
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 4;
$output .= $itoa64[$c1];
$c1 = ($c2 & 0x0f) << 2;
$c2 = ord($input[$i++]);
$c1 |= $c2 >> 6;
$output .= $itoa64[$c1];
$output .= $itoa64[$c2 & 0x3f];
} while (1);
return $output;
}
function HashPassword($password)
{
$random = '';
if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
$random = $this->get_random_bytes(16);
$hash =
crypt($password, $this->gensalt_blowfish($random));
if (strlen($hash) == 60)
return $hash;
}
if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
if (strlen($random) < 3)
$random = $this->get_random_bytes(3);
$hash =
crypt($password, $this->gensalt_extended($random));
if (strlen($hash) == 20)
return $hash;
}
if (strlen($random) < 6)
$random = $this->get_random_bytes(6);
$hash =
$this->crypt_private($password,
$this->gensalt_private($random));
if (strlen($hash) == 34)
return $hash;
# Returning '*' on error is safe here, but would _not_ be safe
# in a crypt(3)-like function used _both_ for generating new
# hashes and for validating passwords against existing hashes.
return '*';
}
function CheckPassword($password, $stored_hash)
{
$hash = $this->crypt_private($password, $stored_hash);
if ($hash[0] == '*')
$hash = crypt($password, $stored_hash);
return $hash === $stored_hash;
}
}
?>
3.알고리즘 분석
(1)wordpress 암호 화 된 비밀문서 형식:$P$B12345678huiyw4r7qhfuhs8yjmd6ef$P$912345678huiyw4r7qhfuhs8yjmd6ef 1 단:$P$형식 고정 2 단:한 글자 만 있 습 니 다.phop 버 전이 5.0 이상 이면 B 이 고 그렇지 않 으 면 9 세 번 째 단계 입 니 다.8 비트 salt 네 번 째 단계:22 비트,실제 암호 화 된 암호 화 방법 phop 버 전 은 5.0 보다 높 습 니 다.
$hash = md5($salt . $password, TRUE);
do
{
$hash = md5($hash . $password, TRUE);
} while (--$count);
[주]"."php 에서 연결 연산 입 니 다.
파라미터 TRUR 는 암호 화 결 과 를 16 바이트 바 이 너 리 로 표시 합 니 다.
count 2 의 13 차방:8192
php 버 전 5.0 이하
$hash = pack('H*', md5($salt . $password));
do
{
$hash = pack('H*', md5($hash . $password));
} while (--$count);
[주]phop 이 5.0 md5 보다 낮 으 면 32 비트 16 진수 문자열 형식 으로 돌아 갑 니 다.
pack(H*)은 md5 결 과 를 2 진법 으로 바꾼다.
count 취 2 의 11 차방:2048
상기 방법 으로 얻 은$hash 를 base 64 암호 화 합 니 다:
(3)wordpress 의 base 64 알고리즘
64 비트 문자 표 는 특수 합 니 다.일반적인 문자 표 순서 와 차이 가 있 습 니 다.
itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
//input 즉 hash,count=16
function encode64($input, $count)
{
$output = '';
$i = 0;
do
{
$value = ord($input[$i++]);// acsii
$output .= $this->itoa64[$value & 0x3f];
if ($i < $count)
$value |= ord($input[$i]) << 8;
$output .= $this->itoa64[($value >> 6) & 0x3f];
if ($i++ >= $count)
break;
if ($i < $count)
$value |= ord($input[$i]) << 16;
$output .= $this->itoa64[($value >> 12) & 0x3f];
if ($i++ >= $count)
break;
$output .= $this->itoa64[($value >> 18) & 0x3f];
} while ($i < $count);
return $output;
}
상기 방법 으로 22 비트 암호 화 된 비밀 번 호 를 얻 을 수 있 습 니 다.
4.C 로 wordpress 의 암호 화 실현
다음은 본인 이 C 로 구현 한 코드 입 니 다.오류 가 있 으 면 지적 해 주 십시오!
wordpress.c 파일:
#include <stdio.h>
#include <string.h>
#include "md5.h"
#include "wordpress.h"
#define WORDPRESS_MD5_CHAR_NUM 16
unsigned char base64Char[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
void md5_to_unsigned_char(unsigned char *hash)
{
int i;
unsigned char md5[17];
for (i = 0; i < 16; i++)
{
if (hash[2*i] >= '0' && hash[2*i] <= '9')
md5[i] = (hash[2*i] - '0') << 4;
else if (hash[2*i] >= 'a' && hash[2*i] <= 'f')
md5[i] = (hash[2*i] - 'a') <<4;
if (hash[2*i+1] >= '0' && hash[2*i+1] <= '9')
md5[i] = md5[i] | ((hash[2*i+1] - '0') & 0x0f);
else if (hash[2*i+1] >= 'a' && hash[2*i+1] <= 'f')
md5[i] = md5[i] | ((hash[2*i+1] - 'a') & 0x0f);
}
md5[16] = '\0';
for (i = 0; i < 16; i++)
hash[i] = md5[i];
hash[16] = '\0';
}
void base64Encode(unsigned char *md5, unsigned char *result)
{
int num_24bits = 5;
int i;
for (i = 0; i < num_24bits; ++i)
{
result[4 * i + 0] = base64Char[(md5[3 * i] >> 2) & 0x3F];
result[4 * i + 1] = base64Char[(((md5[3 * i] & 0x3) << 4) | (md5[3 * i + 1] >> 4)) & 0x3F];
result[4 * i + 2] = base64Char[((md5[3 * i + 1] << 2) | (md5[3 * i + 2] >> 6)) & 0x3F];
result[4 * i + 3] = base64Char[md5[3 * i + 2] & 0x3F];
}
result[20] = base64Char[md5[15] >> 2];
result[21] = base64Char[(md5[15] << 4) & 0x3F];
result[22] = '\0';
}
int wordpress( unsigned char * salt, unsigned char *passwd, int count, unsigned char *code )
{
int i, j;
char symbol;
unsigned char buffer[100];
unsigned char base64_code[23];
int len = strlen( (char *)passwd );
if (strlen( (char *)salt ) != 8)
{
printf("illegal salt!
");
return 1;
}
if (count != 8192 && count != 2048)
{
printf("illegal count!
");
return 1;
}
//first time use md5 function with salt
strcpy( (char *)buffer, (char *)salt );
strcat( (char *)buffer, (char *)passwd );
MD5( buffer, strlen( (char *)buffer), buffer, 0 );
md5_to_unsigned_char( buffer );
//count times md5 function
for (i = 0; i < count; i++)
{
memcpy( (void *)&buffer[WORDPRESS_MD5_CHAR_NUM], passwd, len );
MD5( buffer, WORDPRESS_MD5_CHAR_NUM + len, buffer, 0 );
md5_to_unsigned_char( buffer );
}
memcpy( (void *)code, buffer, 32);
base64Encode( buffer, base64_code );
if (count == 8192)
symbol = 'B';
else if(count == 2048)
symbol = '9';
strcpy( (char *)code, "$P$" );
code[3] = symbol;
code[4] = '\0';
strcat( (char *)code, (char *)salt);
memcpy( (void *)&code[12], base64_code, 22);
return 0;
}
이전에 자신 이 쓴 md5 코드 를 동봉 합 니 다:
#include "md5.h"
#include <stdio.h>
#include <memory.h>
#include <string.h>
#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x^y^z)
#define I(x,y,z) (y ^ (x | ~z))
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
#define FF(a,b,c,d,x,s,ac) \
{ \
a += F(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define GG(a,b,c,d,x,s,ac) \
{ \
a += G(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define HH(a,b,c,d,x,s,ac) \
{ \
a += H(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define II(a,b,c,d,x,s,ac) \
{ \
a += I(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
void MD5Init(MD5_CTX *context);
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);
void MD5Final(MD5_CTX *context,unsigned char digest[16]);
void MD5Transform(unsigned int state[4],unsigned char block[64]);
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len);
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len);
unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
void MD5Init(MD5_CTX *context)
{
context->count[0] = 0;
context->count[1] = 0;
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
}
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)
{
unsigned int i = 0,index = 0,partlen = 0;
index = (context->count[0] >> 3) & 0x3F;
partlen = 64 - index;
context->count[0] += inputlen << 3;
if(context->count[0] < (inputlen << 3))
context->count[1]++;
context->count[1] += inputlen >> 29;
if(inputlen >= partlen)
{
memcpy(&context->buffer[index],input,partlen);
MD5Transform(context->state,context->buffer);
for(i = partlen;i+64 <= inputlen;i+=64)
MD5Transform(context->state,&input[i]);
index = 0;
}
else
{
i = 0;
}
memcpy(&context->buffer[index],&input[i],inputlen-i);
}
void MD5Final(MD5_CTX *context,unsigned char digest[16])
{
unsigned int index = 0,padlen = 0;
unsigned char bits[8];
index = (context->count[0] >> 3) & 0x3F;
padlen = (index < 56)?(56-index):(120-index);
MD5Encode(bits,context->count,8);
MD5Update(context,PADDING,padlen);
MD5Update(context,bits,8);
MD5Encode(digest,context->state,16);
}
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[j] = input[i] & 0xFF;
output[j+1] = (input[i] >> 8) & 0xFF;
output[j+2] = (input[i] >> 16) & 0xFF;
output[j+3] = (input[i] >> 24) & 0xFF;
i++;
j+=4;
}
}
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[i] = (input[j]) |
(input[j+1] << 8) |
(input[j+2] << 16) |
(input[j+3] << 24);
i++;
j+=4;
}
}
void MD5Transform(unsigned int state[4],unsigned char block[64])
{
unsigned int a = state[0];
unsigned int b = state[1];
unsigned int c = state[2];
unsigned int d = state[3];
unsigned int x[64];
MD5Decode(x,block,64);
FF(a, b, c, d, x[ 0], 7, 0xd76aa478);
FF(d, a, b, c, x[ 1], 12, 0xe8c7b756);
FF(c, d, a, b, x[ 2], 17, 0x242070db);
FF(b, c, d, a, x[ 3], 22, 0xc1bdceee);
FF(a, b, c, d, x[ 4], 7, 0xf57c0faf);
FF(d, a, b, c, x[ 5], 12, 0x4787c62a);
FF(c, d, a, b, x[ 6], 17, 0xa8304613);
FF(b, c, d, a, x[ 7], 22, 0xfd469501);
FF(a, b, c, d, x[ 8], 7, 0x698098d8);
FF(d, a, b, c, x[ 9], 12, 0x8b44f7af);
FF(c, d, a, b, x[10], 17, 0xffff5bb1);
FF(b, c, d, a, x[11], 22, 0x895cd7be);
FF(a, b, c, d, x[12], 7, 0x6b901122);
FF(d, a, b, c, x[13], 12, 0xfd987193);
FF(c, d, a, b, x[14], 17, 0xa679438e);
FF(b, c, d, a, x[15], 22, 0x49b40821);
GG(a, b, c, d, x[ 1], 5, 0xf61e2562);
GG(d, a, b, c, x[ 6], 9, 0xc040b340);
GG(c, d, a, b, x[11], 14, 0x265e5a51);
GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa);
GG(a, b, c, d, x[ 5], 5, 0xd62f105d);
GG(d, a, b, c, x[10], 9, 0x2441453);
GG(c, d, a, b, x[15], 14, 0xd8a1e681);
GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8);
GG(a, b, c, d, x[ 9], 5, 0x21e1cde6);
GG(d, a, b, c, x[14], 9, 0xc33707d6);
GG(c, d, a, b, x[ 3], 14, 0xf4d50d87);
GG(b, c, d, a, x[ 8], 20, 0x455a14ed);
GG(a, b, c, d, x[13], 5, 0xa9e3e905);
GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8);
GG(c, d, a, b, x[ 7], 14, 0x676f02d9);
GG(b, c, d, a, x[12], 20, 0x8d2a4c8a);
HH(a, b, c, d, x[ 5], 4, 0xfffa3942);
HH(d, a, b, c, x[ 8], 11, 0x8771f681);
HH(c, d, a, b, x[11], 16, 0x6d9d6122);
HH(b, c, d, a, x[14], 23, 0xfde5380c);
HH(a, b, c, d, x[ 1], 4, 0xa4beea44);
HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9);
HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60);
HH(b, c, d, a, x[10], 23, 0xbebfbc70);
HH(a, b, c, d, x[13], 4, 0x289b7ec6);
HH(d, a, b, c, x[ 0], 11, 0xeaa127fa);
HH(c, d, a, b, x[ 3], 16, 0xd4ef3085);
HH(b, c, d, a, x[ 6], 23, 0x4881d05);
HH(a, b, c, d, x[ 9], 4, 0xd9d4d039);
HH(d, a, b, c, x[12], 11, 0xe6db99e5);
HH(c, d, a, b, x[15], 16, 0x1fa27cf8);
HH(b, c, d, a, x[ 2], 23, 0xc4ac5665);
II(a, b, c, d, x[ 0], 6, 0xf4292244);
II(d, a, b, c, x[ 7], 10, 0x432aff97);
II(c, d, a, b, x[14], 15, 0xab9423a7);
II(b, c, d, a, x[ 5], 21, 0xfc93a039);
II(a, b, c, d, x[12], 6, 0x655b59c3);
II(d, a, b, c, x[ 3], 10, 0x8f0ccc92);
II(c, d, a, b, x[10], 15, 0xffeff47d);
II(b, c, d, a, x[ 1], 21, 0x85845dd1);
II(a, b, c, d, x[ 8], 6, 0x6fa87e4f);
II(d, a, b, c, x[15], 10, 0xfe2ce6e0);
II(c, d, a, b, x[ 6], 15, 0xa3014314);
II(b, c, d, a, x[13], 21, 0x4e0811a1);
II(a, b, c, d, x[ 4], 6, 0xf7537e82);
II(d, a, b, c, x[11], 10, 0xbd3af235);
II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb);
II(b, c, d, a, x[ 9], 21, 0xeb86d391);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
void MD5(unsigned char * buf, unsigned int len, unsigned char *out, int type)
{
int i;
MD5_CTX md5;
unsigned char digest[16];
char hex[]="0123456789abcdef";
char HEX[]="0123456789ABCDEF";
MD5Init(&md5);
MD5Update(&md5, buf,len);
MD5Final(&md5, digest);
if (type == 0)
{
for (i = 0; i < 16; i++)
{
out[i+i] = hex[digest[i] >> 4];
out[i+i+1] = hex[digest[i] & 0x0f];
}
}
else if (type == 1)
{
for (i = 0; i < 16; i++)
{
out[i+i] = HEX[digest[i] >> 4];
out[i+i+1] = HEX[digest[i] & 0x0f];
}
}
out[i+i] = '\0';
}
테스트 코드:
#include <stdio.h>
#include "wordpress.h"
int main()
{
unsigned char passwd[] = "12345678";
unsigned char salt[] = "12345687";
unsigned char code[40];
wordpress(salt, passwd, 8192, code);
printf("code: %s
", code);
return 0;
}
[출처] https://intrepidgeeks.com/tutorial/part-1-analysis-of-wordpress-user-encryption-principle-and-algorithm
테스트 코드:
#include <stdio.h>
#include "wordpress.h"
int main()
{
unsigned char passwd[] = "12345678";
unsigned char salt[] = "12345687";
unsigned char code[40];
wordpress(salt, passwd, 8192, code);
printf("code: %s
", code);
return 0;
}
[출처] https://intrepidgeeks.com/tutorial/part-1-analysis-of-wordpress-user-encryption-principle-and-algorithm