I want PHP and Go to produce the same output. Go's encryption code should be RC4-MD5 I tried to decrypt it with py-openssl, and the result was the same as Go. I think maybe php-openssl lacks streaming.
this is my Go code.
iv, _ := hex.DecodeString("8ec07bf03d8c5eaf37619aaac1cb305c") // iv
key := evpBytesToKey("123456", 16) // build Key
fmt.Println(hex.EncodeToString(key))//e10adc3949ba59abbe56e057f20f883e
h := md5.New()
h.Write(key)
h.Write(iv)
rc4key := h.Sum(nil)
fmt.Println(hex.EncodeToString(rc4key)) //fd0eb4cfd6b0174968d9979781d95670
cipher, _ := rc4.NewCipher(rc4key) // rc4key
text, _ := hex.DecodeString("f1")
dist := make([]byte, len(text))
cipher.XORKeyStream(dist, text);
fmt.Println(hex.EncodeToString(dist)) // 03
text, _ = hex.DecodeString("f1")
dist = make([]byte, len(text))
cipher.XORKeyStream(dist, text);
fmt.Println(hex.EncodeToString(dist)) // 0e
Output
e10adc3949ba59abbe56e057f20f883e
fd0eb4cfd6b0174968d9979781d95670
03
0e
func evpBytesToKey(password string, keyLen int) (key []byte) {
const md5Len = 16
cnt := (keyLen-1)/md5Len + 1
m := make([]byte, cnt*md5Len)
copy(m, md5sum([]byte(password)))
// Repeatedly call md5 until bytes generated is enough.
// Each call to md5 uses data: prev md5 sum + password.
d := make([]byte, md5Len+len(password))
start := 0
for i := 1; i < cnt; i++ {
start += md5Len
copy(d, m[start-md5Len:start])
copy(d[md5Len:], password)
copy(m[start:], md5sum(d))
}
return m[:keyLen]
}
func md5sum(d []byte) []byte {
h := md5.New()
h.Write(d)
return h.Sum(nil)
}
this is my php code.
//base64_decode('jsB78D2MXq83YZqqwcswXA==') == hex.DecodeString("8ec07bf03d8c5eaf37619aaac1cb305c")
$iv = base64_decode('jsB78D2MXq83YZqqwcswXA==');
$key = evpBytesToKey("123456", 16);
var_dump(binToHex($key));
$rc4key = md5($key . $iv, true);
var_dump(binToHex($rc4key));
//base64_decode('8Q==') == hex.DecodeString("f1")
var_dump(binToHex(openssl_decrypt('8Q==', 'rc4', $rc4key, 0)));
var_dump(binToHex(openssl_decrypt('8Q==', 'rc4', $rc4key, 0)));
Output
string(32) "e10adc3949ba59abbe56e057f20f883e"
string(32) "fd0eb4cfd6b0174968d9979781d95670"
string(2) "03"
string(2) "03"
function evpBytesToKey(string $password, int $keyLen)
{
$md5Len = 16;
$cnt = (int)(($keyLen - 1) / $md5Len + 1);
$m = md5($password, true);
$start = 0;
for ($i = 1; $i < $cnt; $i++) {
//Todo
}
return substr($m, 0, $keyLen);
}
function binToHex(string $src)
{
//from go/src/encoding/hex/hex.go
$dst = '';
$hextable = '0123456789abcdef';
$len = strlen($src);
for ($i = 0; $i < $len; $i++) {
$v = ord($src[$i]);
$dst[$i * 2] = $hextable[$v >> 4];
$dst[$i * 2 + 1] = $hextable[$v & 0x0f];
}
return $dst;
}
I expect php output to be the same as Go's.