Subversion Repositories oidplus

Rev

Rev 1085 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
635 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
1084 daniel-mar 5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
635 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
1050 daniel-mar 20
namespace ViaThinkSoft\OIDplus;
635 daniel-mar 21
 
1086 daniel-mar 22
// phpcs:disable PSR1.Files.SideEffects
23
\defined('INSIDE_OIDPLUS') or die;
24
// phpcs:enable PSR1.Files.SideEffects
25
 
635 daniel-mar 26
class OIDplusAuthPluginPhpGenericSaltedHex extends OIDplusAuthPlugin {
27
 
1085 daniel-mar 28
        private function getBinaryHash($s_authmethod, $hashalgo, $salt, $check_password) {
635 daniel-mar 29
                if ($s_authmethod == 'A1a') {
30
                        // This auth method can be used by you if you migrate users from another software solution into OIDplus
1085 daniel-mar 31
                        // A1a#hashalgo:X with X being H(salt+password) in hex- or base64-notation
635 daniel-mar 32
                        // Attention: With some hash algorithms, prepending the salt makes it vulnerable against length-extension-attacks
1085 daniel-mar 33
                        return hash($hashalgo, $salt.$check_password, true);
635 daniel-mar 34
                } else if ($s_authmethod == 'A1b') {
35
                        // This auth method can be used by you if you migrate users from another software solution into OIDplus
1085 daniel-mar 36
                        // A1b#hashalgo:X with X being H(password+salt) in hex- or base64-notation
37
                        return hash($hashalgo, $check_password.$salt, true);
635 daniel-mar 38
                } else if ($s_authmethod == 'A1c') {
39
                        // This auth method can be used by you if you migrate users from another software solution into OIDplus
1085 daniel-mar 40
                        // A1c#hashalgo:X with X being H(salt+password+salt) in hex- or base64-notation
41
                        return hash($hashalgo, $salt.$check_password.$salt, true);
635 daniel-mar 42
                } else if ($s_authmethod == 'A1d') {
43
                        // This auth method can be used by you if you migrate users from another software solution into OIDplus
1085 daniel-mar 44
                        // A1d#hashalgo:X with X being H_HMAC(password,salt) in hex- or base64-notation
45
                        return hash_hmac($hashalgo, $check_password, $salt, true);
635 daniel-mar 46
                } else {
47
                        // Invalid auth code
48
                        return false;
49
                }
1085 daniel-mar 50
        }
635 daniel-mar 51
 
1085 daniel-mar 52
        public function verify(OIDplusRAAuthInfo $authInfo, $check_password) {
53
                $authKey = $authInfo->getAuthKey();
54
                $salt = $authInfo->getSalt();
55
                @list($s_authmethod, $s_authkey) = explode('#', $authKey, 2);
56
 
57
                $hashalgo = explode(':', $s_authkey, 2)[0];
58
 
59
                $bindata = $this->getBinaryHash($s_authmethod, $hashalgo, $salt, $check_password);
60
                if ($bindata === false) return false;
61
 
1084 daniel-mar 62
                return hash_equals($s_authkey, $hashalgo.':'.strtolower(bin2hex($bindata)))
63
                    || hash_equals($s_authkey, $hashalgo.':'.base64_encode($bindata))
64
                    || hash_equals($s_authkey, $hashalgo.':'.rtrim(base64_encode($bindata),'='));
635 daniel-mar 65
        }
66
 
67
        public function generate($password): OIDplusRAAuthInfo {
68
                $preferred_hash_algos = array(
69
                    // sorted by priority
1084 daniel-mar 70
                    'sha3-512',
71
                    'sha3-384',
635 daniel-mar 72
                    'sha3-256',
73
                    'sha3-224',
1084 daniel-mar 74
                    'sha512',
635 daniel-mar 75
                    'sha512/256',
76
                    'sha512/224',
1084 daniel-mar 77
                    'sha384',
635 daniel-mar 78
                    'sha256',
79
                    'sha224',
80
                    'sha1',
81
                    'md5'
82
                );
1085 daniel-mar 83
 
84
                $s_authmethod = 'A1c';
85
 
635 daniel-mar 86
                $algos = hash_algos();
87
                $hashalgo = null;
88
                foreach ($preferred_hash_algos as $a) {
89
                        if (in_array($a, $algos)) {
90
                                $hashalgo = $a;
91
                                break;
92
                        }
93
                }
94
                if (is_null($hashalgo)) {
95
                        throw new OIDplusException(_L('No fitting hash algorithm found'));
96
                }
1085 daniel-mar 97
                $salt = bin2hex(OIDplus::authUtils()->getRandomBytes(50)); // DB field ra.salt is limited to 100 chars (= 50 bytes)
635 daniel-mar 98
 
1085 daniel-mar 99
                $bindata = $this->getBinaryHash($s_authmethod, $hashalgo, $salt, $password);
100
                if ($bindata === false) throw new OIDplusException(_L('Invalid hash auth method'));
101
 
102
                $calc_authkey = $s_authmethod.'#'.$hashalgo.':'.strtolower(bin2hex($bindata));
103
 
1084 daniel-mar 104
                if (strlen($calc_authkey) > 100) {
105
                        // Since our database field is limited to 100 bytes, use base64 instead of hex
1085 daniel-mar 106
                        $calc_authkey = $s_authmethod.'#'.$hashalgo.':'.base64_encode($bindata);
1084 daniel-mar 107
                        $calc_authkey = rtrim($calc_authkey,'=');
108
                        /*
1085 daniel-mar 109
                        [Base64] sha3-512   authkey length in hex is 141 and length in base64 is 99
110
                        [Base64] sha3-384   authkey length in hex is 109 and length in base64 is 77
111
                        [Hex]    sha3-256   authkey length in hex is  77 and length in base64 is 56
112
                        [Hex]    sha3-224   authkey length in hex is  69 and length in base64 is 51
113
                        [Base64] sha512     authkey length in hex is 139 and length in base64 is 97
114
                        [Hex]    sha512/256 authkey length in hex is  79 and length in base64 is 58
115
                        [Hex]    sha512/224 authkey length in hex is  71 and length in base64 is 53
116
                        [Base64] sha384     authkey length in hex is 107 and length in base64 is 75
117
                        [Hex]    sha256     authkey length in hex is  75 and length in base64 is 54
118
                        [Hex]    sha224     authkey length in hex is  67 and length in base64 is 49
119
                        [Hex]    sha1       authkey length in hex is  49 and length in base64 is 36
120
                        [Hex]    md5        authkey length in hex is  40 and length in base64 is 30
1084 daniel-mar 121
                        */
122
                }
123
 
1085 daniel-mar 124
                return new OIDplusRAAuthInfo($salt, $calc_authkey);
635 daniel-mar 125
        }
126
 
127
}