VirtualBox

source: vbox/trunk/src/VBox/Runtime/tools/RTMkPasswd.cpp@ 102297

Last change on this file since 102297 was 102297, checked in by vboxsync, 12 months ago

IPRT/crypto/shacrypt: Better string length checks for RTCrShaCryptXXXToString(). bugref:10551

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.3 KB
Line 
1/* $Id: RTMkPasswd.cpp 102297 2023-11-24 16:32:03Z vboxsync $ */
2/** @file
3 * IPRT - Makes passwords.
4 */
5
6/*
7 * Copyright (C) 2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37#include <iprt/buildconfig.h>
38#include <iprt/crypto/shacrypt.h>
39#include <iprt/err.h>
40#include <iprt/initterm.h>
41#include <iprt/getopt.h>
42#include <iprt/mem.h>
43#include <iprt/message.h>
44#include <iprt/rand.h>
45#include <iprt/sha.h>
46#include <iprt/stream.h>
47#include <iprt/string.h>
48
49
50/** Method type. */
51typedef enum RTMKPASSWORD_METHODTYPE
52{
53 RTMKPASSWORD_METHODTYPE_SHA256,
54 RTMKPASSWORD_METHODTYPE_SHA512
55} RTMKPASSWORD_METHODTYPE;
56
57
58int main(int argc, char **argv)
59{
60 RTR3InitExe(argc, &argv, 0);
61
62 /*
63 * Process options.
64 */
65 static const RTGETOPTDEF aOpts[] =
66 {
67 { "--help", 'h', RTGETOPT_REQ_NOTHING },
68 { "--salt", 'S', RTGETOPT_REQ_STRING },
69 { "--rounds", 'R', RTGETOPT_REQ_UINT32 },
70 { "--method", 'm', RTGETOPT_REQ_STRING },
71 { "--version", 'V', RTGETOPT_REQ_NOTHING }
72 };
73
74 RTGETOPTSTATE GetState;
75 int rc = RTGetOptInit(&GetState, argc, argv, aOpts, RT_ELEMENTS(aOpts), 1 /*idxFirst*/, 0 /*fFlags - must not sort! */);
76 AssertRCReturn(rc, RTEXITCODE_INIT);
77
78 const char *pszKey = NULL;
79 char szSalt[RT_SHACRYPT_MAX_SALT_LEN + 1];
80 const char *pszSalt = NULL;
81 uint32_t cRounds = RT_SHACRYPT_DEFAULT_ROUNDS;
82 RTMKPASSWORD_METHODTYPE enmMethod = RTMKPASSWORD_METHODTYPE_SHA512; /* Go with strongest by default. */
83
84 int ch;
85 RTGETOPTUNION ValueUnion;
86 while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
87 {
88 switch (ch)
89 {
90 case 'S':
91 {
92 if (!pszSalt)
93 {
94 pszSalt = ValueUnion.psz;
95 }
96 else
97 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Salt already specified!\n");
98 break;
99 }
100
101 case 'R':
102 {
103 cRounds = ValueUnion.u32;
104 if (cRounds < RT_SHACRYPT_DEFAULT_ROUNDS)
105 RTMsgWarning("Using less rounds than the default (%zu) isn't a good idea!!\n",
106 RT_SHACRYPT_DEFAULT_ROUNDS);
107 break;
108 }
109
110 case 'm':
111 {
112 const char *pszMethod = ValueUnion.psz;
113 if (!RTStrICmp(pszMethod, "sha256"))
114 enmMethod = RTMKPASSWORD_METHODTYPE_SHA256;
115 else if (!RTStrICmp(pszMethod, "sha512"))
116 enmMethod = RTMKPASSWORD_METHODTYPE_SHA512;
117 else if (!RTStrICmp(pszMethod, "help"))
118 {
119 RTPrintf("Supported methods: sha256, sha512\n");
120 }
121 else
122 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Sorry, method '%s' not implemented yet!\n", pszMethod);
123 break;
124 }
125
126 case 'h':
127 {
128 RTPrintf("Usage: %s [options] password\n"
129 "\n"
130 "Options:\n"
131 " -S <salt>, --salt <salt>\n"
132 " Salt to use.\n"
133 " -R, --rounds\n"
134 " Number of rounds to use.\n"
135 " -m <type>, --method <type>\n"
136 " Method to use for creation. sha512 is the default.\n"
137 " If <type> is 'help', then the list of all available methods are printed.\n"
138 " -h, --help\n"
139 " This help screen.\n"
140 , argv[0]);
141 return RTEXITCODE_SUCCESS;
142 }
143
144 case 'V':
145 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
146 return RTEXITCODE_SUCCESS;
147
148 case VINF_GETOPT_NOT_OPTION:
149 {
150 if (!pszKey)
151 pszKey = ValueUnion.psz;
152 else
153 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Password already specified!\n");
154 break;
155 }
156
157 default:
158 return RTGetOptPrintError(ch, &ValueUnion);
159 }
160 }
161
162 if (!pszKey)
163 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No password specified!\n");
164 if (!pszSalt)
165 {
166 static const char aRange[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!?+\"%&/()[]{}=#";
167 for (unsigned i = 0; i < RT_SHACRYPT_MAX_SALT_LEN; i++) /* Always go with a strong salt by default. */
168 szSalt[i] = aRange[RTRandU32Ex(0, sizeof(aRange) - 2)];
169 pszSalt = szSalt;
170 }
171 else if (strlen(pszSalt) < RT_SHACRYPT_MIN_SALT_LEN)
172 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Salt is too short (must be at least %zu characters)!\n",
173 RT_SHACRYPT_MIN_SALT_LEN);
174 else if (strlen(pszSalt) > RT_SHACRYPT_MAX_SALT_LEN)
175 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Salt is too long (must be less or equal than %zu characters)!\n",
176 RT_SHACRYPT_MAX_SALT_LEN);
177
178 uint8_t abDigest[RTSHA512_HASH_SIZE];
179 char szResult[RTSHA512_DIGEST_LEN + 1];
180
181 switch (enmMethod)
182 {
183 case RTMKPASSWORD_METHODTYPE_SHA256:
184 {
185 rc = RTCrShaCrypt256(pszKey, pszSalt, cRounds, abDigest);
186 if (RT_SUCCESS(rc))
187 rc = RTCrShaCrypt256ToString(abDigest, pszSalt, cRounds, szResult, sizeof(szResult));
188 break;
189 }
190
191 case RTMKPASSWORD_METHODTYPE_SHA512:
192 {
193 rc = RTCrShaCrypt512(pszKey, pszSalt, cRounds, abDigest);
194 if (RT_SUCCESS(rc))
195 rc = RTCrShaCrypt512ToString(abDigest, pszSalt, cRounds, szResult, sizeof(szResult));
196 break;
197 }
198
199 default:
200 AssertFailed();
201 break;
202 }
203
204 if (RT_SUCCESS(rc))
205 {
206 RTPrintf("%s\n", szResult);
207 }
208 else
209 RTMsgError("Failed with %Rrc\n", rc);
210
211 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
212}
213
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette