1<?php 2/** 3 * Helper Component for Securelogin Dokuwiki Plugin 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Mikhail I. Izmestev 7 * @maintainer Matt Bagley 8 * 9 * @see also https://www.dokuwiki.org/plugin:securelogin 10 */ 11// must be run within Dokuwiki 12if(!defined('DOKU_INC')) die(); 13 14/** 15 * This is the base class for all syntax classes, providing some general stuff 16 */ 17class helper_plugin_securelogin extends DokuWiki_Plugin { 18 protected $_keyFile; 19 protected $_keyIFile; 20 protected $_key = null; 21 protected $_keyInfo = null; 22 protected $_workCorrect = false; 23 protected $_canWork = false; 24 25 /** 26 * constructor 27 */ 28 function __construct() { 29 global $conf; 30 31 $this->_keyIFile = $conf['cachedir'].'/securelogin.ini'; 32 $this->_keyFile = $conf['cachedir'].'/securelogin.key'; 33 34 if( true 35 && function_exists("openssl_pkey_export_to_file") 36 && function_exists("openssl_pkey_get_private") 37 && function_exists("openssl_pkey_new") 38 && function_exists("openssl_private_decrypt") 39 ) 40 $this->_canWork = true; 41 } 42 43 function canWork() { 44 return $this->_canWork; 45 } 46 47 function haveKey($onlyPublic = false) { 48 if($onlyPublic) { 49 if($this->_keyInfo) return true; 50 51 if(file_exists($this->_keyIFile)) { 52 $this->_keyInfo = parse_ini_file($this->_keyIFile); 53 return true; 54 } 55 } 56 57 if(!$this->_key && file_exists($this->_keyFile)) { 58 $this->_key = openssl_pkey_get_private(file_get_contents($this->_keyFile)); 59 if($this->_key) { 60 if(file_exists($this->_keyIFile)) 61 $this->_keyInfo = parse_ini_file($this->_keyIFile); 62 else 63 $this->savePublicInfo($this->getPublicKeyInfo(file_get_contents($this->_keyFile))); 64 } 65 } 66 return null != $this->_key; 67 } 68 69 function getKeyLengths() { 70 return array('default' => 'default', '512' => '512', '1024' => '1024', '2048' => '2048'); 71 } 72 73 function generateKey($length) { 74 if(!array_key_exists($length, $this->getKeyLengths())) { 75 msg("Error key length $length not supported", -1); 76 return; 77 } 78 79 $newkey = @openssl_pkey_new(('default' == $length)?array():array('private_key_bits' => intval($length))); 80 81 if(!$newkey) { 82 msg('Error generating new key', -1); 83 return; 84 } 85 if(!openssl_pkey_export_to_file($newkey, $this->_keyFile)) 86 msg('Error export new key', -1); 87 else { 88 $this->_key = openssl_pkey_get_private(file_get_contents($this->_keyFile)); 89 $this->savePublicInfo($this->getPublicKeyInfo(file_get_contents($this->_keyFile))); 90 } 91 } 92 93 function getKeyLength() { 94 return (strlen($this->getModulus())-2)*4; 95 } 96 97 function getModulus() { 98 return ($this->haveKey(true))?$this->_keyInfo['modulus']:null; 99 } 100 101 function getExponent() { 102 return ($this->haveKey(true))?$this->_keyInfo['exponent']:null; 103 } 104 105 function savePublicInfo($info) { 106 $fpinfo = fopen($this->_keyIFile, "w"); 107 foreach($info as $key => $val) { 108 fprintf($fpinfo, "%s=\"%s\"\n", $key, $val); 109 } 110 fclose($fpinfo); 111 $this->_keyInfo = parse_ini_file($this->_keyIFile); 112 } 113 114 function decrypt($text) { 115 if($this->haveKey()) 116 openssl_private_decrypt(base64_decode($text), $decoded, $this->_key); 117 return $decoded; 118 } 119 120 function decodeBER($bin) { 121 function my_unpack($format, &$bin, $length) { 122 $res = unpack($format, $bin); 123 $bin = substr($bin, $length); 124 return $res; 125 } 126 127 function readBER(&$bin) { 128 if(!strlen($bin)) return FALSE; 129 130 $data = my_unpack("C1type/c1length", $bin, 2); 131 132 if($data['length'] < 0) { 133 $count = $data['length'] & 0x7F; 134 $data['length'] = 0; 135 while($count) { 136 $data['length'] <<= 8; 137 $tmp = my_unpack("C1length", $bin, 1); 138 $data['length'] += $tmp['length']; 139 $count--; 140 } 141 } 142 143 switch($data['type']) { 144 case 0x30: 145 $data['value'] = array(); 146 do { 147 $tmp = readBER($bin); 148 if($tmp) 149 $data['value'][] = $tmp; 150 } while($tmp); 151 break; 152 case 0x03: 153 $null = my_unpack("C1", $bin, 1); 154 $data['value'] = readBER($bin); 155 break; 156 case 0x04: 157 $data['value'] = readBER($bin); 158 break; 159 default: 160 $count = $data['length']; 161 while($count) { 162 $tmp = my_unpack("C1data", $bin, 1); 163 $data['value'] .= sprintf("%02X", $tmp['data']); 164 $count--; 165 } 166 } 167 return $data; 168 } 169 return readBER($bin); 170 } 171 172 function getPublicKeyInfo($pubkey) { 173 function findKeyInfo($data, &$pubkeyinfo) { 174 if($data['type'] == 48) { 175 if(count($data['value']) != 9) { 176 foreach($data['value'] as $subdata) { 177 if(findKeyInfo($subdata, $pubkeyinfo)) 178 return true; 179 } 180 } else { 181 $pubkeyinfo = array( 182 "modulus" => $data['value'][1]['value'], 183 "exponent" => $data['value'][2]['value'], 184 ); 185 return true; 186 } 187 } 188 elseif($data['type'] == 4) { 189 return findKeyInfo($data['value'], $pubkeyinfo); 190 } 191 return false; 192 } 193 194 $pubkey = preg_split("(-\n|\n-)", $pubkey); 195 $binary = base64_decode($pubkey[1]); 196 197 $data = $this->decodeBER($binary); 198 199 findKeyInfo($data, $pubkeyinfo); 200/* 201 $pubkeyinfo = array( 202 "modulus" => $data['value'][1]['value'][2]['value']['value'][1]['value'], 203 "exponent" => $data['value'][1]['value'][2]['value']['value'][2]['value'], 204 ); 205*/ 206 return $pubkeyinfo; 207 } 208 209 function workCorrect($yes = false) { 210 if($yes) 211 $this->_workCorrect = true; 212 return $this->_workCorrect; 213 } 214} 215