Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of wolfSSL by
ripemd.c
00001 /* ripemd.c 00002 * 00003 * Copyright (C) 2006-2016 wolfSSL Inc. 00004 * 00005 * This file is part of wolfSSL. 00006 * 00007 * wolfSSL is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License as published by 00009 * the Free Software Foundation; either version 2 of the License, or 00010 * (at your option) any later version. 00011 * 00012 * wolfSSL is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU General Public License 00018 * along with this program; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA 00020 */ 00021 00022 00023 00024 #ifdef HAVE_CONFIG_H 00025 #include <config.h> 00026 #endif 00027 00028 #include <wolfssl/wolfcrypt/settings.h> 00029 00030 #ifdef WOLFSSL_RIPEMD 00031 00032 #include <wolfssl/wolfcrypt/ripemd.h> 00033 #ifdef NO_INLINE 00034 #include <wolfssl/wolfcrypt/misc.h> 00035 #else 00036 #define WOLFSSL_MISC_INCLUDED 00037 #include <wolfcrypt/src/misc.c> 00038 #endif 00039 00040 00041 00042 void wc_InitRipeMd(RipeMd* ripemd) 00043 { 00044 ripemd->digest[0] = 0x67452301L; 00045 ripemd->digest[1] = 0xEFCDAB89L; 00046 ripemd->digest[2] = 0x98BADCFEL; 00047 ripemd->digest[3] = 0x10325476L; 00048 ripemd->digest[4] = 0xC3D2E1F0L; 00049 00050 ripemd->buffLen = 0; 00051 ripemd->loLen = 0; 00052 ripemd->hiLen = 0; 00053 } 00054 00055 00056 /* for all */ 00057 #define F(x, y, z) (x ^ y ^ z) 00058 #define G(x, y, z) (z ^ (x & (y^z))) 00059 #define H(x, y, z) (z ^ (x | ~y)) 00060 #define I(x, y, z) (y ^ (z & (x^y))) 00061 #define J(x, y, z) (x ^ (y | ~z)) 00062 00063 #define k0 0 00064 #define k1 0x5a827999 00065 #define k2 0x6ed9eba1 00066 #define k3 0x8f1bbcdc 00067 #define k4 0xa953fd4e 00068 #define k5 0x50a28be6 00069 #define k6 0x5c4dd124 00070 #define k7 0x6d703ef3 00071 #define k8 0x7a6d76e9 00072 #define k9 0 00073 00074 /* for 160 and 320 */ 00075 #define Subround(f, a, b, c, d, e, x, s, k) \ 00076 a += f(b, c, d) + x + k;\ 00077 a = rotlFixed((word32)a, s) + e;\ 00078 c = rotlFixed((word32)c, 10U) 00079 00080 static void Transform(RipeMd* ripemd) 00081 { 00082 word32 a1, b1, c1, d1, e1, a2, b2, c2, d2, e2; 00083 a1 = a2 = ripemd->digest[0]; 00084 b1 = b2 = ripemd->digest[1]; 00085 c1 = c2 = ripemd->digest[2]; 00086 d1 = d2 = ripemd->digest[3]; 00087 e1 = e2 = ripemd->digest[4]; 00088 00089 Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[ 0], 11, k0); 00090 Subround(F, e1, a1, b1, c1, d1, ripemd->buffer[ 1], 14, k0); 00091 Subround(F, d1, e1, a1, b1, c1, ripemd->buffer[ 2], 15, k0); 00092 Subround(F, c1, d1, e1, a1, b1, ripemd->buffer[ 3], 12, k0); 00093 Subround(F, b1, c1, d1, e1, a1, ripemd->buffer[ 4], 5, k0); 00094 Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[ 5], 8, k0); 00095 Subround(F, e1, a1, b1, c1, d1, ripemd->buffer[ 6], 7, k0); 00096 Subround(F, d1, e1, a1, b1, c1, ripemd->buffer[ 7], 9, k0); 00097 Subround(F, c1, d1, e1, a1, b1, ripemd->buffer[ 8], 11, k0); 00098 Subround(F, b1, c1, d1, e1, a1, ripemd->buffer[ 9], 13, k0); 00099 Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[10], 14, k0); 00100 Subround(F, e1, a1, b1, c1, d1, ripemd->buffer[11], 15, k0); 00101 Subround(F, d1, e1, a1, b1, c1, ripemd->buffer[12], 6, k0); 00102 Subround(F, c1, d1, e1, a1, b1, ripemd->buffer[13], 7, k0); 00103 Subround(F, b1, c1, d1, e1, a1, ripemd->buffer[14], 9, k0); 00104 Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[15], 8, k0); 00105 00106 Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 7], 7, k1); 00107 Subround(G, d1, e1, a1, b1, c1, ripemd->buffer[ 4], 6, k1); 00108 Subround(G, c1, d1, e1, a1, b1, ripemd->buffer[13], 8, k1); 00109 Subround(G, b1, c1, d1, e1, a1, ripemd->buffer[ 1], 13, k1); 00110 Subround(G, a1, b1, c1, d1, e1, ripemd->buffer[10], 11, k1); 00111 Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 6], 9, k1); 00112 Subround(G, d1, e1, a1, b1, c1, ripemd->buffer[15], 7, k1); 00113 Subround(G, c1, d1, e1, a1, b1, ripemd->buffer[ 3], 15, k1); 00114 Subround(G, b1, c1, d1, e1, a1, ripemd->buffer[12], 7, k1); 00115 Subround(G, a1, b1, c1, d1, e1, ripemd->buffer[ 0], 12, k1); 00116 Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 9], 15, k1); 00117 Subround(G, d1, e1, a1, b1, c1, ripemd->buffer[ 5], 9, k1); 00118 Subround(G, c1, d1, e1, a1, b1, ripemd->buffer[ 2], 11, k1); 00119 Subround(G, b1, c1, d1, e1, a1, ripemd->buffer[14], 7, k1); 00120 Subround(G, a1, b1, c1, d1, e1, ripemd->buffer[11], 13, k1); 00121 Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 8], 12, k1); 00122 00123 Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[ 3], 11, k2); 00124 Subround(H, c1, d1, e1, a1, b1, ripemd->buffer[10], 13, k2); 00125 Subround(H, b1, c1, d1, e1, a1, ripemd->buffer[14], 6, k2); 00126 Subround(H, a1, b1, c1, d1, e1, ripemd->buffer[ 4], 7, k2); 00127 Subround(H, e1, a1, b1, c1, d1, ripemd->buffer[ 9], 14, k2); 00128 Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[15], 9, k2); 00129 Subround(H, c1, d1, e1, a1, b1, ripemd->buffer[ 8], 13, k2); 00130 Subround(H, b1, c1, d1, e1, a1, ripemd->buffer[ 1], 15, k2); 00131 Subround(H, a1, b1, c1, d1, e1, ripemd->buffer[ 2], 14, k2); 00132 Subround(H, e1, a1, b1, c1, d1, ripemd->buffer[ 7], 8, k2); 00133 Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[ 0], 13, k2); 00134 Subround(H, c1, d1, e1, a1, b1, ripemd->buffer[ 6], 6, k2); 00135 Subround(H, b1, c1, d1, e1, a1, ripemd->buffer[13], 5, k2); 00136 Subround(H, a1, b1, c1, d1, e1, ripemd->buffer[11], 12, k2); 00137 Subround(H, e1, a1, b1, c1, d1, ripemd->buffer[ 5], 7, k2); 00138 Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[12], 5, k2); 00139 00140 Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 1], 11, k3); 00141 Subround(I, b1, c1, d1, e1, a1, ripemd->buffer[ 9], 12, k3); 00142 Subround(I, a1, b1, c1, d1, e1, ripemd->buffer[11], 14, k3); 00143 Subround(I, e1, a1, b1, c1, d1, ripemd->buffer[10], 15, k3); 00144 Subround(I, d1, e1, a1, b1, c1, ripemd->buffer[ 0], 14, k3); 00145 Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 8], 15, k3); 00146 Subround(I, b1, c1, d1, e1, a1, ripemd->buffer[12], 9, k3); 00147 Subround(I, a1, b1, c1, d1, e1, ripemd->buffer[ 4], 8, k3); 00148 Subround(I, e1, a1, b1, c1, d1, ripemd->buffer[13], 9, k3); 00149 Subround(I, d1, e1, a1, b1, c1, ripemd->buffer[ 3], 14, k3); 00150 Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 7], 5, k3); 00151 Subround(I, b1, c1, d1, e1, a1, ripemd->buffer[15], 6, k3); 00152 Subround(I, a1, b1, c1, d1, e1, ripemd->buffer[14], 8, k3); 00153 Subround(I, e1, a1, b1, c1, d1, ripemd->buffer[ 5], 6, k3); 00154 Subround(I, d1, e1, a1, b1, c1, ripemd->buffer[ 6], 5, k3); 00155 Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 2], 12, k3); 00156 00157 Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[ 4], 9, k4); 00158 Subround(J, a1, b1, c1, d1, e1, ripemd->buffer[ 0], 15, k4); 00159 Subround(J, e1, a1, b1, c1, d1, ripemd->buffer[ 5], 5, k4); 00160 Subround(J, d1, e1, a1, b1, c1, ripemd->buffer[ 9], 11, k4); 00161 Subround(J, c1, d1, e1, a1, b1, ripemd->buffer[ 7], 6, k4); 00162 Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[12], 8, k4); 00163 Subround(J, a1, b1, c1, d1, e1, ripemd->buffer[ 2], 13, k4); 00164 Subround(J, e1, a1, b1, c1, d1, ripemd->buffer[10], 12, k4); 00165 Subround(J, d1, e1, a1, b1, c1, ripemd->buffer[14], 5, k4); 00166 Subround(J, c1, d1, e1, a1, b1, ripemd->buffer[ 1], 12, k4); 00167 Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[ 3], 13, k4); 00168 Subround(J, a1, b1, c1, d1, e1, ripemd->buffer[ 8], 14, k4); 00169 Subround(J, e1, a1, b1, c1, d1, ripemd->buffer[11], 11, k4); 00170 Subround(J, d1, e1, a1, b1, c1, ripemd->buffer[ 6], 8, k4); 00171 Subround(J, c1, d1, e1, a1, b1, ripemd->buffer[15], 5, k4); 00172 Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[13], 6, k4); 00173 00174 Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[ 5], 8, k5); 00175 Subround(J, e2, a2, b2, c2, d2, ripemd->buffer[14], 9, k5); 00176 Subround(J, d2, e2, a2, b2, c2, ripemd->buffer[ 7], 9, k5); 00177 Subround(J, c2, d2, e2, a2, b2, ripemd->buffer[ 0], 11, k5); 00178 Subround(J, b2, c2, d2, e2, a2, ripemd->buffer[ 9], 13, k5); 00179 Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[ 2], 15, k5); 00180 Subround(J, e2, a2, b2, c2, d2, ripemd->buffer[11], 15, k5); 00181 Subround(J, d2, e2, a2, b2, c2, ripemd->buffer[ 4], 5, k5); 00182 Subround(J, c2, d2, e2, a2, b2, ripemd->buffer[13], 7, k5); 00183 Subround(J, b2, c2, d2, e2, a2, ripemd->buffer[ 6], 7, k5); 00184 Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[15], 8, k5); 00185 Subround(J, e2, a2, b2, c2, d2, ripemd->buffer[ 8], 11, k5); 00186 Subround(J, d2, e2, a2, b2, c2, ripemd->buffer[ 1], 14, k5); 00187 Subround(J, c2, d2, e2, a2, b2, ripemd->buffer[10], 14, k5); 00188 Subround(J, b2, c2, d2, e2, a2, ripemd->buffer[ 3], 12, k5); 00189 Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[12], 6, k5); 00190 00191 Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[ 6], 9, k6); 00192 Subround(I, d2, e2, a2, b2, c2, ripemd->buffer[11], 13, k6); 00193 Subround(I, c2, d2, e2, a2, b2, ripemd->buffer[ 3], 15, k6); 00194 Subround(I, b2, c2, d2, e2, a2, ripemd->buffer[ 7], 7, k6); 00195 Subround(I, a2, b2, c2, d2, e2, ripemd->buffer[ 0], 12, k6); 00196 Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[13], 8, k6); 00197 Subround(I, d2, e2, a2, b2, c2, ripemd->buffer[ 5], 9, k6); 00198 Subround(I, c2, d2, e2, a2, b2, ripemd->buffer[10], 11, k6); 00199 Subround(I, b2, c2, d2, e2, a2, ripemd->buffer[14], 7, k6); 00200 Subround(I, a2, b2, c2, d2, e2, ripemd->buffer[15], 7, k6); 00201 Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[ 8], 12, k6); 00202 Subround(I, d2, e2, a2, b2, c2, ripemd->buffer[12], 7, k6); 00203 Subround(I, c2, d2, e2, a2, b2, ripemd->buffer[ 4], 6, k6); 00204 Subround(I, b2, c2, d2, e2, a2, ripemd->buffer[ 9], 15, k6); 00205 Subround(I, a2, b2, c2, d2, e2, ripemd->buffer[ 1], 13, k6); 00206 Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[ 2], 11, k6); 00207 00208 Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[15], 9, k7); 00209 Subround(H, c2, d2, e2, a2, b2, ripemd->buffer[ 5], 7, k7); 00210 Subround(H, b2, c2, d2, e2, a2, ripemd->buffer[ 1], 15, k7); 00211 Subround(H, a2, b2, c2, d2, e2, ripemd->buffer[ 3], 11, k7); 00212 Subround(H, e2, a2, b2, c2, d2, ripemd->buffer[ 7], 8, k7); 00213 Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[14], 6, k7); 00214 Subround(H, c2, d2, e2, a2, b2, ripemd->buffer[ 6], 6, k7); 00215 Subround(H, b2, c2, d2, e2, a2, ripemd->buffer[ 9], 14, k7); 00216 Subround(H, a2, b2, c2, d2, e2, ripemd->buffer[11], 12, k7); 00217 Subround(H, e2, a2, b2, c2, d2, ripemd->buffer[ 8], 13, k7); 00218 Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[12], 5, k7); 00219 Subround(H, c2, d2, e2, a2, b2, ripemd->buffer[ 2], 14, k7); 00220 Subround(H, b2, c2, d2, e2, a2, ripemd->buffer[10], 13, k7); 00221 Subround(H, a2, b2, c2, d2, e2, ripemd->buffer[ 0], 13, k7); 00222 Subround(H, e2, a2, b2, c2, d2, ripemd->buffer[ 4], 7, k7); 00223 Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[13], 5, k7); 00224 00225 Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[ 8], 15, k8); 00226 Subround(G, b2, c2, d2, e2, a2, ripemd->buffer[ 6], 5, k8); 00227 Subround(G, a2, b2, c2, d2, e2, ripemd->buffer[ 4], 8, k8); 00228 Subround(G, e2, a2, b2, c2, d2, ripemd->buffer[ 1], 11, k8); 00229 Subround(G, d2, e2, a2, b2, c2, ripemd->buffer[ 3], 14, k8); 00230 Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[11], 14, k8); 00231 Subround(G, b2, c2, d2, e2, a2, ripemd->buffer[15], 6, k8); 00232 Subround(G, a2, b2, c2, d2, e2, ripemd->buffer[ 0], 14, k8); 00233 Subround(G, e2, a2, b2, c2, d2, ripemd->buffer[ 5], 6, k8); 00234 Subround(G, d2, e2, a2, b2, c2, ripemd->buffer[12], 9, k8); 00235 Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[ 2], 12, k8); 00236 Subround(G, b2, c2, d2, e2, a2, ripemd->buffer[13], 9, k8); 00237 Subround(G, a2, b2, c2, d2, e2, ripemd->buffer[ 9], 12, k8); 00238 Subround(G, e2, a2, b2, c2, d2, ripemd->buffer[ 7], 5, k8); 00239 Subround(G, d2, e2, a2, b2, c2, ripemd->buffer[10], 15, k8); 00240 Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[14], 8, k8); 00241 00242 Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[12], 8, k9); 00243 Subround(F, a2, b2, c2, d2, e2, ripemd->buffer[15], 5, k9); 00244 Subround(F, e2, a2, b2, c2, d2, ripemd->buffer[10], 12, k9); 00245 Subround(F, d2, e2, a2, b2, c2, ripemd->buffer[ 4], 9, k9); 00246 Subround(F, c2, d2, e2, a2, b2, ripemd->buffer[ 1], 12, k9); 00247 Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[ 5], 5, k9); 00248 Subround(F, a2, b2, c2, d2, e2, ripemd->buffer[ 8], 14, k9); 00249 Subround(F, e2, a2, b2, c2, d2, ripemd->buffer[ 7], 6, k9); 00250 Subround(F, d2, e2, a2, b2, c2, ripemd->buffer[ 6], 8, k9); 00251 Subround(F, c2, d2, e2, a2, b2, ripemd->buffer[ 2], 13, k9); 00252 Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[13], 6, k9); 00253 Subround(F, a2, b2, c2, d2, e2, ripemd->buffer[14], 5, k9); 00254 Subround(F, e2, a2, b2, c2, d2, ripemd->buffer[ 0], 15, k9); 00255 Subround(F, d2, e2, a2, b2, c2, ripemd->buffer[ 3], 13, k9); 00256 Subround(F, c2, d2, e2, a2, b2, ripemd->buffer[ 9], 11, k9); 00257 Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[11], 11, k9); 00258 00259 c1 = ripemd->digest[1] + c1 + d2; 00260 ripemd->digest[1] = ripemd->digest[2] + d1 + e2; 00261 ripemd->digest[2] = ripemd->digest[3] + e1 + a2; 00262 ripemd->digest[3] = ripemd->digest[4] + a1 + b2; 00263 ripemd->digest[4] = ripemd->digest[0] + b1 + c2; 00264 ripemd->digest[0] = c1; 00265 } 00266 00267 00268 static INLINE void AddLength(RipeMd* ripemd, word32 len) 00269 { 00270 word32 tmp = ripemd->loLen; 00271 if ( (ripemd->loLen += len) < tmp) 00272 ripemd->hiLen++; /* carry low to high */ 00273 } 00274 00275 00276 void wc_RipeMdUpdate(RipeMd* ripemd, const byte* data, word32 len) 00277 { 00278 /* do block size increments */ 00279 byte* local = (byte*)ripemd->buffer; 00280 00281 while (len) { 00282 word32 add = min(len, RIPEMD_BLOCK_SIZE - ripemd->buffLen); 00283 XMEMCPY(&local[ripemd->buffLen], data, add); 00284 00285 ripemd->buffLen += add; 00286 data += add; 00287 len -= add; 00288 00289 if (ripemd->buffLen == RIPEMD_BLOCK_SIZE) { 00290 #ifdef BIG_ENDIAN_ORDER 00291 ByteReverseWords(ripemd->buffer, ripemd->buffer, 00292 RIPEMD_BLOCK_SIZE); 00293 #endif 00294 Transform(ripemd); 00295 AddLength(ripemd, RIPEMD_BLOCK_SIZE); 00296 ripemd->buffLen = 0; 00297 } 00298 } 00299 } 00300 00301 00302 void wc_RipeMdFinal(RipeMd* ripemd, byte* hash) 00303 { 00304 byte* local = (byte*)ripemd->buffer; 00305 00306 AddLength(ripemd, ripemd->buffLen); /* before adding pads */ 00307 00308 local[ripemd->buffLen++] = 0x80; /* add 1 */ 00309 00310 /* pad with zeros */ 00311 if (ripemd->buffLen > RIPEMD_PAD_SIZE) { 00312 XMEMSET(&local[ripemd->buffLen], 0, RIPEMD_BLOCK_SIZE - ripemd->buffLen); 00313 ripemd->buffLen += RIPEMD_BLOCK_SIZE - ripemd->buffLen; 00314 00315 #ifdef BIG_ENDIAN_ORDER 00316 ByteReverseWords(ripemd->buffer, ripemd->buffer, RIPEMD_BLOCK_SIZE); 00317 #endif 00318 Transform(ripemd); 00319 ripemd->buffLen = 0; 00320 } 00321 XMEMSET(&local[ripemd->buffLen], 0, RIPEMD_PAD_SIZE - ripemd->buffLen); 00322 00323 /* put lengths in bits */ 00324 ripemd->loLen = ripemd->loLen << 3; 00325 ripemd->hiLen = (ripemd->loLen >> (8*sizeof(ripemd->loLen) - 3)) + 00326 (ripemd->hiLen << 3); 00327 00328 /* store lengths */ 00329 #ifdef BIG_ENDIAN_ORDER 00330 ByteReverseWords(ripemd->buffer, ripemd->buffer, RIPEMD_BLOCK_SIZE); 00331 #endif 00332 /* ! length ordering dependent on digest endian type ! */ 00333 XMEMCPY(&local[RIPEMD_PAD_SIZE], &ripemd->loLen, sizeof(word32)); 00334 XMEMCPY(&local[RIPEMD_PAD_SIZE + sizeof(word32)], &ripemd->hiLen, 00335 sizeof(word32)); 00336 00337 Transform(ripemd); 00338 #ifdef BIG_ENDIAN_ORDER 00339 ByteReverseWords(ripemd->digest, ripemd->digest, RIPEMD_DIGEST_SIZE); 00340 #endif 00341 XMEMCPY(hash, ripemd->digest, RIPEMD_DIGEST_SIZE); 00342 00343 wc_InitRipeMd(ripemd); /* reset state */ 00344 } 00345 00346 00347 #endif /* WOLFSSL_RIPEMD */ 00348
Generated on Tue Jul 12 2022 23:30:59 by
1.7.2
