3 * @file src/Util/Crypto.php
5 namespace Friendica\Util;
7 use Friendica\Core\Config;
9 require_once 'library/ASNValue.class.php';
10 require_once 'library/asn1.php';
17 // supported algorithms are 'sha256', 'sha1'
19 * @param string $data data
20 * @param string $key key
21 * @param string $alg algorithm
24 public static function rsaSign($data, $key, $alg = 'sha256')
26 openssl_sign($data, $sig, $key, (($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg));
31 * @param string $data data
32 * @param string $sig signature
33 * @param string $key key
34 * @param string $alg algorithm
37 public static function rsaVerify($data, $sig, $key, $alg = 'sha256')
39 return openssl_verify($data, $sig, $key, (($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg));
43 * @param string $Der der formatted string
44 * @param string $Private key type optional, default false
47 private static function DerToPem($Der, $Private = false)
50 $Der = base64_encode($Der);
52 $lines = str_split($Der, 65);
53 $body = implode("\n", $lines);
55 $title = $Private ? 'RSA PRIVATE KEY' : 'PUBLIC KEY';
57 $result = "-----BEGIN {$title}-----\n";
58 $result .= $body . "\n";
59 $result .= "-----END {$title}-----\n";
65 * @param string $Der der formatted string
68 private static function DerToRsa($Der)
71 $Der = base64_encode($Der);
73 $lines = str_split($Der, 64);
74 $body = implode("\n", $lines);
76 $title = 'RSA PUBLIC KEY';
78 $result = "-----BEGIN {$title}-----\n";
79 $result .= $body . "\n";
80 $result .= "-----END {$title}-----\n";
86 * @param string $Modulus modulo
87 * @param string $PublicExponent exponent
90 private static function pkcs8Encode($Modulus, $PublicExponent)
93 $modulus = new ASNValue(ASNValue::TAG_INTEGER);
94 $modulus->SetIntBuffer($Modulus);
95 $publicExponent = new ASNValue(ASNValue::TAG_INTEGER);
96 $publicExponent->SetIntBuffer($PublicExponent);
97 $keySequenceItems = array($modulus, $publicExponent);
98 $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE);
99 $keySequence->SetSequence($keySequenceItems);
101 $bitStringValue = $keySequence->Encode();
102 $bitStringValue = chr(0x00) . $bitStringValue; //Add unused bits byte
103 $bitString = new ASNValue(ASNValue::TAG_BITSTRING);
104 $bitString->Value = $bitStringValue;
106 $bodyValue = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00" . $bitString->Encode();
107 $body = new ASNValue(ASNValue::TAG_SEQUENCE);
108 $body->Value = $bodyValue;
109 //Get DER encoded public key:
110 $PublicDER = $body->Encode();
115 * @param string $Modulus modulo
116 * @param string $PublicExponent exponent
119 private static function pkcs1Encode($Modulus, $PublicExponent)
121 //Encode key sequence
122 $modulus = new ASNValue(ASNValue::TAG_INTEGER);
123 $modulus->SetIntBuffer($Modulus);
124 $publicExponent = new ASNValue(ASNValue::TAG_INTEGER);
125 $publicExponent->SetIntBuffer($PublicExponent);
126 $keySequenceItems = array($modulus, $publicExponent);
127 $keySequence = new ASNValue(ASNValue::TAG_SEQUENCE);
128 $keySequence->SetSequence($keySequenceItems);
130 $bitStringValue = $keySequence->Encode();
131 return $bitStringValue;
135 * @param string $m modulo
136 * @param string $e exponent
139 public static function meToPem($m, $e)
141 $der = self::pkcs8Encode($m, $e);
142 $key = self::DerToPem($der, false);
147 * @param string $key key
148 * @param string $m modulo reference
149 * @param object $e exponent reference
152 private static function pubRsaToMe($key, &$m, &$e)
154 $lines = explode("\n", $key);
156 unset($lines[count($lines)]);
157 $x = base64_decode(implode('', $lines));
159 $r = ASN_BASE::parseASNString($x);
161 $m = base64url_decode($r[0]->asnData[0]->asnData);
162 $e = base64url_decode($r[0]->asnData[1]->asnData);
166 * @param string $key key
169 public static function rsaToPem($key)
171 self::pubRsaToMe($key, $m, $e);
172 return self::meToPem($m, $e);
176 * @param string $key key
179 private static function pemToRsa($key)
181 self::pemToMe($key, $m, $e);
182 return self::meToRsa($m, $e);
186 * @param string $key key
187 * @param string $m modulo reference
188 * @param string $e exponent reference
191 private static function pemToMe($key, &$m, &$e)
193 $lines = explode("\n", $key);
195 unset($lines[count($lines)]);
196 $x = base64_decode(implode('', $lines));
198 $r = ASN_BASE::parseASNString($x);
200 $m = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[0]->asnData);
201 $e = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[1]->asnData);
205 * @param string $m modulo
206 * @param string $e exponent
209 private static function meToRsa($m, $e)
211 $der = self::pkcs1Encode($m, $e);
212 $key = self::DerToRsa($der);
217 * @param string $pubkey public key
220 public static function salmonKey($pubkey)
222 self::pemToMe($pubkey, $m, $e);
223 return 'RSA' . '.' . base64url_encode($m, true) . '.' . base64url_encode($e, true);
227 * @param integer $bits number of bits
230 public static function newKeypair($bits)
232 $openssl_options = array(
233 'digest_alg' => 'sha1',
234 'private_key_bits' => $bits,
235 'encrypt_key' => false
238 $conf = Config::get('system', 'openssl_conf_file');
240 $openssl_options['config'] = $conf;
242 $result = openssl_pkey_new($openssl_options);
244 if (empty($result)) {
245 logger('new_keypair: failed');
250 $response = array('prvkey' => '', 'pubkey' => '');
252 openssl_pkey_export($result, $response['prvkey']);
255 $pkey = openssl_pkey_get_details($result);
256 $response['pubkey'] = $pkey["key"];