Friendica Communications Platform (please note that this is a clone of the repository at github, issues are handled there) https://friendi.ca
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
8.2 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. <?php
  2. require_once('library/ASNValue.class.php');
  3. require_once('library/asn1.php');
  4. // supported algorithms are 'sha256', 'sha1'
  5. function rsa_sign($data,$key,$alg = 'sha256') {
  6. $sig = '';
  7. if (version_compare(PHP_VERSION, '5.3.0', '>=') || $alg === 'sha1') {
  8. openssl_sign($data,$sig,$key,(($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg));
  9. }
  10. else {
  11. if(strlen($key) < 1024 || extension_loaded('gmp')) {
  12. require_once('library/phpsec/Crypt/RSA.php');
  13. $rsa = new CRYPT_RSA();
  14. $rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1;
  15. $rsa->setHash($alg);
  16. $rsa->loadKey($key);
  17. $sig = $rsa->sign($data);
  18. }
  19. else {
  20. logger('rsa_sign: insecure algorithm used. Please upgrade PHP to 5.3');
  21. openssl_private_encrypt(hex2bin('3031300d060960864801650304020105000420') . hash('sha256',$data,true), $sig, $key);
  22. }
  23. }
  24. return $sig;
  25. }
  26. function rsa_verify($data,$sig,$key,$alg = 'sha256') {
  27. if (version_compare(PHP_VERSION, '5.3.0', '>=') || $alg === 'sha1') {
  28. $verify = openssl_verify($data,$sig,$key,(($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg));
  29. }
  30. else {
  31. if(strlen($key) <= 300 || extension_loaded('gmp')) {
  32. require_once('library/phpsec/Crypt/RSA.php');
  33. $rsa = new CRYPT_RSA();
  34. $rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1;
  35. $rsa->setHash($alg);
  36. $rsa->loadKey($key);
  37. $verify = $rsa->verify($data,$sig);
  38. }
  39. else {
  40. // fallback sha256 verify for PHP < 5.3 and large key lengths
  41. $rawsig = '';
  42. openssl_public_decrypt($sig,$rawsig,$key);
  43. $verify = (($rawsig && substr($rawsig,-32) === hash('sha256',$data,true)) ? true : false);
  44. }
  45. }
  46. return $verify;
  47. }
  48. function DerToPem($Der, $Private=false)
  49. {
  50. //Encode:
  51. $Der = base64_encode($Der);
  52. //Split lines:
  53. $lines = str_split($Der, 65);
  54. $body = implode("\n", $lines);
  55. //Get title:
  56. $title = $Private? 'RSA PRIVATE KEY' : 'PUBLIC KEY';
  57. //Add wrapping:
  58. $result = "-----BEGIN {$title}-----\n";
  59. $result .= $body . "\n";
  60. $result .= "-----END {$title}-----\n";
  61. return $result;
  62. }
  63. function DerToRsa($Der)
  64. {
  65. //Encode:
  66. $Der = base64_encode($Der);
  67. //Split lines:
  68. $lines = str_split($Der, 64);
  69. $body = implode("\n", $lines);
  70. //Get title:
  71. $title = 'RSA PUBLIC KEY';
  72. //Add wrapping:
  73. $result = "-----BEGIN {$title}-----\n";
  74. $result .= $body . "\n";
  75. $result .= "-----END {$title}-----\n";
  76. return $result;
  77. }
  78. function pkcs8_encode($Modulus,$PublicExponent) {
  79. //Encode key sequence
  80. $modulus = new ASNValue(ASNValue::TAG_INTEGER);
  81. $modulus->SetIntBuffer($Modulus);
  82. $publicExponent = new ASNValue(ASNValue::TAG_INTEGER);
  83. $publicExponent->SetIntBuffer($PublicExponent);
  84. $keySequenceItems = array($modulus, $publicExponent);
  85. $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE);
  86. $keySequence->SetSequence($keySequenceItems);
  87. //Encode bit string
  88. $bitStringValue = $keySequence->Encode();
  89. $bitStringValue = chr(0x00) . $bitStringValue; //Add unused bits byte
  90. $bitString = new ASNValue(ASNValue::TAG_BITSTRING);
  91. $bitString->Value = $bitStringValue;
  92. //Encode body
  93. $bodyValue = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00" . $bitString->Encode();
  94. $body = new ASNValue(ASNValue::TAG_SEQUENCE);
  95. $body->Value = $bodyValue;
  96. //Get DER encoded public key:
  97. $PublicDER = $body->Encode();
  98. return $PublicDER;
  99. }
  100. function pkcs1_encode($Modulus,$PublicExponent) {
  101. //Encode key sequence
  102. $modulus = new ASNValue(ASNValue::TAG_INTEGER);
  103. $modulus->SetIntBuffer($Modulus);
  104. $publicExponent = new ASNValue(ASNValue::TAG_INTEGER);
  105. $publicExponent->SetIntBuffer($PublicExponent);
  106. $keySequenceItems = array($modulus, $publicExponent);
  107. $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE);
  108. $keySequence->SetSequence($keySequenceItems);
  109. //Encode bit string
  110. $bitStringValue = $keySequence->Encode();
  111. return $bitStringValue;
  112. }
  113. function metopem($m,$e) {
  114. $der = pkcs8_encode($m,$e);
  115. $key = DerToPem($der,false);
  116. return $key;
  117. }
  118. function pubrsatome($key,&$m,&$e) {
  119. require_once('library/asn1.php');
  120. require_once('include/salmon.php');
  121. $lines = explode("\n",$key);
  122. unset($lines[0]);
  123. unset($lines[count($lines)]);
  124. $x = base64_decode(implode('',$lines));
  125. $r = ASN_BASE::parseASNString($x);
  126. $m = base64url_decode($r[0]->asnData[0]->asnData);
  127. $e = base64url_decode($r[0]->asnData[1]->asnData);
  128. }
  129. function rsatopem($key) {
  130. pubrsatome($key,$m,$e);
  131. return(metopem($m,$e));
  132. }
  133. function pemtorsa($key) {
  134. pemtome($key,$m,$e);
  135. return(metorsa($m,$e));
  136. }
  137. function pemtome($key,&$m,&$e) {
  138. require_once('include/salmon.php');
  139. $lines = explode("\n",$key);
  140. unset($lines[0]);
  141. unset($lines[count($lines)]);
  142. $x = base64_decode(implode('',$lines));
  143. $r = ASN_BASE::parseASNString($x);
  144. $m = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[0]->asnData);
  145. $e = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[1]->asnData);
  146. }
  147. function metorsa($m,$e) {
  148. $der = pkcs1_encode($m,$e);
  149. $key = DerToRsa($der);
  150. return $key;
  151. }
  152. function salmon_key($pubkey) {
  153. pemtome($pubkey,$m,$e);
  154. return 'RSA' . '.' . base64url_encode($m,true) . '.' . base64url_encode($e,true) ;
  155. }
  156. if(! function_exists('aes_decrypt')) {
  157. function aes_decrypt($val,$ky)
  158. {
  159. $key="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
  160. for($a=0;$a<strlen($ky);$a++)
  161. $key[$a%16]=chr(ord($key[$a%16]) ^ ord($ky[$a]));
  162. $mode = MCRYPT_MODE_ECB;
  163. $enc = MCRYPT_RIJNDAEL_128;
  164. $dec = @mcrypt_decrypt($enc, $key, $val, $mode, @mcrypt_create_iv( @mcrypt_get_iv_size($enc, $mode), MCRYPT_DEV_URANDOM ) );
  165. return rtrim($dec,(( ord(substr($dec,strlen($dec)-1,1))>=0 and ord(substr($dec, strlen($dec)-1,1))<=16)? chr(ord( substr($dec,strlen($dec)-1,1))):null));
  166. }}
  167. if(! function_exists('aes_encrypt')) {
  168. function aes_encrypt($val,$ky)
  169. {
  170. $key="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
  171. for($a=0;$a<strlen($ky);$a++)
  172. $key[$a%16]=chr(ord($key[$a%16]) ^ ord($ky[$a]));
  173. $mode=MCRYPT_MODE_ECB;
  174. $enc=MCRYPT_RIJNDAEL_128;
  175. $val=str_pad($val, (16*(floor(strlen($val) / 16)+(strlen($val) % 16==0?2:1))), chr(16-(strlen($val) % 16)));
  176. return mcrypt_encrypt($enc, $key, $val, $mode, mcrypt_create_iv( mcrypt_get_iv_size($enc, $mode), MCRYPT_DEV_URANDOM));
  177. }}
  178. function pkcs5_pad ($text, $blocksize)
  179. {
  180. $pad = $blocksize - (strlen($text) % $blocksize);
  181. return $text . str_repeat(chr($pad), $pad);
  182. }
  183. function pkcs5_unpad($text)
  184. {
  185. $pad = ord($text{strlen($text)-1});
  186. if ($pad > strlen($text)) return false;
  187. if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false;
  188. return substr($text, 0, -1 * $pad);
  189. }
  190. function AES256CBC_encrypt($data,$key,$iv) {
  191. return mcrypt_encrypt(
  192. MCRYPT_RIJNDAEL_128,
  193. str_pad($key,32,"\0"),
  194. pkcs5_pad($data,16),
  195. MCRYPT_MODE_CBC,
  196. str_pad($iv,16,"\0"));
  197. }
  198. function AES256CBC_decrypt($data,$key,$iv) {
  199. return pkcs5_unpad(mcrypt_decrypt(
  200. MCRYPT_RIJNDAEL_128,
  201. str_pad($key,32,"\0"),
  202. $data,
  203. MCRYPT_MODE_CBC,
  204. str_pad($iv,16,"\0")));
  205. }
  206. function aes_encapsulate($data,$pubkey) {
  207. $key = random_string(32,RANDOM_STRING_TEXT);
  208. $iv = random_string(16,RANDOM_STRING_TEXT);
  209. $result['data'] = base64url_encode(AES256CBC_encrypt($data,$key,$iv),true);
  210. openssl_public_encrypt($key,$k,$pubkey);
  211. $result['key'] = base64url_encode($k,true);
  212. openssl_public_encrypt($iv,$i,$pubkey);
  213. $result['iv'] = base64url_encode($i,true);
  214. return $result;
  215. }
  216. function aes_unencapsulate($data,$prvkey) {
  217. openssl_private_decrypt(base64url_decode($data['key']),$k,$prvkey);
  218. openssl_private_decrypt(base64url_decode($data['iv']),$i,$prvkey);
  219. return AES256CBC_decrypt(base64url_decode($data['data']),$k,$i);
  220. }
  221. // This has been superceded.
  222. function zot_encapsulate($data,$envelope,$pubkey) {
  223. $res = aes_encapsulate($data,$pubkey);
  224. return <<< EOT
  225. <?xml version='1.0' encoding='UTF-8'?>
  226. <zot:msg xmlns:zot='http://purl.org/zot/1.0'>
  227. <zot:key>{$res['key']}</zot:key>
  228. <zot:iv>{$res['iv']}</zot:iv>
  229. <zot:env>$s1</zot:env>
  230. <zot:sig key_id="$keyid">$sig</zot:sig>
  231. <zot:alg>AES-256-CBC</zot:alg>
  232. <zot:data type='application/magic-envelope+xml'>{$res['data']}</zot:data>
  233. </zot:msg>
  234. EOT;
  235. }
  236. // so has this
  237. function zot_unencapsulate($data,$prvkey) {
  238. $ret = array();
  239. $c = array();
  240. $x = parse_xml_string($data);
  241. $c = array('key' => $x->key,'iv' => $x->iv,'data' => $x->data);
  242. openssl_private_decrypt(base64url_decode($x->sender),$s,$prvkey);
  243. $ret['sender'] = $s;
  244. $ret['data'] = aes_unencapsulate($x,$prvkey);
  245. return $ret;
  246. }