Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/PyNaCl-1.6.2-py3.11-linux-x86_64.egg/nacl/bindings/crypto_box.py: 17%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

159 statements  

1# Copyright 2013 Donald Stufft and individual contributors 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14from __future__ import annotations 

15 

16from nacl import exceptions as exc 

17from nacl._sodium import ffi, lib 

18from nacl.exceptions import ensure 

19 

20__all__ = ["crypto_box", "crypto_box_keypair"] 

21 

22 

23crypto_box_SECRETKEYBYTES: int = lib.crypto_box_secretkeybytes() 

24crypto_box_PUBLICKEYBYTES: int = lib.crypto_box_publickeybytes() 

25crypto_box_SEEDBYTES: int = lib.crypto_box_seedbytes() 

26crypto_box_NONCEBYTES: int = lib.crypto_box_noncebytes() 

27crypto_box_ZEROBYTES: int = lib.crypto_box_zerobytes() 

28crypto_box_BOXZEROBYTES: int = lib.crypto_box_boxzerobytes() 

29crypto_box_BEFORENMBYTES: int = lib.crypto_box_beforenmbytes() 

30crypto_box_SEALBYTES: int = lib.crypto_box_sealbytes() 

31crypto_box_MACBYTES: int = lib.crypto_box_macbytes() 

32 

33 

34def crypto_box_keypair() -> tuple[bytes, bytes]: 

35 """ 

36 Returns a randomly generated public and secret key. 

37 

38 :rtype: (bytes(public_key), bytes(secret_key)) 

39 """ 

40 pk = ffi.new("unsigned char[]", crypto_box_PUBLICKEYBYTES) 

41 sk = ffi.new("unsigned char[]", crypto_box_SECRETKEYBYTES) 

42 

43 rc = lib.crypto_box_keypair(pk, sk) 

44 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError) 

45 

46 return ( 

47 ffi.buffer(pk, crypto_box_PUBLICKEYBYTES)[:], 

48 ffi.buffer(sk, crypto_box_SECRETKEYBYTES)[:], 

49 ) 

50 

51 

52def crypto_box_seed_keypair(seed: bytes) -> tuple[bytes, bytes]: 

53 """ 

54 Returns a (public, secret) key pair deterministically generated 

55 from an input ``seed``. 

56 

57 .. warning:: The seed **must** be high-entropy; therefore, 

58 its generator **must** be a cryptographic quality 

59 random function like, for example, :func:`~nacl.utils.random`. 

60 

61 .. warning:: The seed **must** be protected and remain secret. 

62 Anyone who knows the seed is really in possession of 

63 the corresponding PrivateKey. 

64 

65 

66 :param seed: bytes 

67 :rtype: (bytes(public_key), bytes(secret_key)) 

68 """ 

69 ensure(isinstance(seed, bytes), "seed must be bytes", raising=TypeError) 

70 

71 if len(seed) != crypto_box_SEEDBYTES: 

72 raise exc.ValueError("Invalid seed") 

73 

74 pk = ffi.new("unsigned char[]", crypto_box_PUBLICKEYBYTES) 

75 sk = ffi.new("unsigned char[]", crypto_box_SECRETKEYBYTES) 

76 

77 rc = lib.crypto_box_seed_keypair(pk, sk, seed) 

78 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError) 

79 

80 return ( 

81 ffi.buffer(pk, crypto_box_PUBLICKEYBYTES)[:], 

82 ffi.buffer(sk, crypto_box_SECRETKEYBYTES)[:], 

83 ) 

84 

85 

86def crypto_box(message: bytes, nonce: bytes, pk: bytes, sk: bytes) -> bytes: 

87 """ 

88 Encrypts and returns a message ``message`` using the secret key ``sk``, 

89 public key ``pk``, and the nonce ``nonce``. 

90 

91 :param message: bytes 

92 :param nonce: bytes 

93 :param pk: bytes 

94 :param sk: bytes 

95 :rtype: bytes 

96 """ 

97 if len(nonce) != crypto_box_NONCEBYTES: 

98 raise exc.ValueError("Invalid nonce size") 

99 

100 if len(pk) != crypto_box_PUBLICKEYBYTES: 

101 raise exc.ValueError("Invalid public key") 

102 

103 if len(sk) != crypto_box_SECRETKEYBYTES: 

104 raise exc.ValueError("Invalid secret key") 

105 

106 padded = (b"\x00" * crypto_box_ZEROBYTES) + message 

107 ciphertext = ffi.new("unsigned char[]", len(padded)) 

108 

109 rc = lib.crypto_box(ciphertext, padded, len(padded), nonce, pk, sk) 

110 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError) 

111 

112 return ffi.buffer(ciphertext, len(padded))[crypto_box_BOXZEROBYTES:] 

113 

114 

115def crypto_box_open( 

116 ciphertext: bytes, nonce: bytes, pk: bytes, sk: bytes 

117) -> bytes: 

118 """ 

119 Decrypts and returns an encrypted message ``ciphertext``, using the secret 

120 key ``sk``, public key ``pk``, and the nonce ``nonce``. 

121 

122 :param ciphertext: bytes 

123 :param nonce: bytes 

124 :param pk: bytes 

125 :param sk: bytes 

126 :rtype: bytes 

127 """ 

128 if len(nonce) != crypto_box_NONCEBYTES: 

129 raise exc.ValueError("Invalid nonce size") 

130 

131 if len(pk) != crypto_box_PUBLICKEYBYTES: 

132 raise exc.ValueError("Invalid public key") 

133 

134 if len(sk) != crypto_box_SECRETKEYBYTES: 

135 raise exc.ValueError("Invalid secret key") 

136 

137 padded = (b"\x00" * crypto_box_BOXZEROBYTES) + ciphertext 

138 plaintext = ffi.new("unsigned char[]", len(padded)) 

139 

140 res = lib.crypto_box_open(plaintext, padded, len(padded), nonce, pk, sk) 

141 ensure( 

142 res == 0, 

143 "An error occurred trying to decrypt the message", 

144 raising=exc.CryptoError, 

145 ) 

146 

147 return ffi.buffer(plaintext, len(padded))[crypto_box_ZEROBYTES:] 

148 

149 

150def crypto_box_beforenm(pk: bytes, sk: bytes) -> bytes: 

151 """ 

152 Computes and returns the shared key for the public key ``pk`` and the 

153 secret key ``sk``. This can be used to speed up operations where the same 

154 set of keys is going to be used multiple times. 

155 

156 :param pk: bytes 

157 :param sk: bytes 

158 :rtype: bytes 

159 """ 

160 if len(pk) != crypto_box_PUBLICKEYBYTES: 

161 raise exc.ValueError("Invalid public key") 

162 

163 if len(sk) != crypto_box_SECRETKEYBYTES: 

164 raise exc.ValueError("Invalid secret key") 

165 

166 k = ffi.new("unsigned char[]", crypto_box_BEFORENMBYTES) 

167 

168 rc = lib.crypto_box_beforenm(k, pk, sk) 

169 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError) 

170 

171 return ffi.buffer(k, crypto_box_BEFORENMBYTES)[:] 

172 

173 

174def crypto_box_afternm(message: bytes, nonce: bytes, k: bytes) -> bytes: 

175 """ 

176 Encrypts and returns the message ``message`` using the shared key ``k`` and 

177 the nonce ``nonce``. 

178 

179 :param message: bytes 

180 :param nonce: bytes 

181 :param k: bytes 

182 :rtype: bytes 

183 """ 

184 if len(nonce) != crypto_box_NONCEBYTES: 

185 raise exc.ValueError("Invalid nonce") 

186 

187 if len(k) != crypto_box_BEFORENMBYTES: 

188 raise exc.ValueError("Invalid shared key") 

189 

190 padded = b"\x00" * crypto_box_ZEROBYTES + message 

191 ciphertext = ffi.new("unsigned char[]", len(padded)) 

192 

193 rc = lib.crypto_box_afternm(ciphertext, padded, len(padded), nonce, k) 

194 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError) 

195 

196 return ffi.buffer(ciphertext, len(padded))[crypto_box_BOXZEROBYTES:] 

197 

198 

199def crypto_box_open_afternm( 

200 ciphertext: bytes, nonce: bytes, k: bytes 

201) -> bytes: 

202 """ 

203 Decrypts and returns the encrypted message ``ciphertext``, using the shared 

204 key ``k`` and the nonce ``nonce``. 

205 

206 :param ciphertext: bytes 

207 :param nonce: bytes 

208 :param k: bytes 

209 :rtype: bytes 

210 """ 

211 if len(nonce) != crypto_box_NONCEBYTES: 

212 raise exc.ValueError("Invalid nonce") 

213 

214 if len(k) != crypto_box_BEFORENMBYTES: 

215 raise exc.ValueError("Invalid shared key") 

216 

217 padded = (b"\x00" * crypto_box_BOXZEROBYTES) + ciphertext 

218 plaintext = ffi.new("unsigned char[]", len(padded)) 

219 

220 res = lib.crypto_box_open_afternm(plaintext, padded, len(padded), nonce, k) 

221 ensure( 

222 res == 0, 

223 "An error occurred trying to decrypt the message", 

224 raising=exc.CryptoError, 

225 ) 

226 

227 return ffi.buffer(plaintext, len(padded))[crypto_box_ZEROBYTES:] 

228 

229 

230def crypto_box_easy( 

231 message: bytes, nonce: bytes, pk: bytes, sk: bytes 

232) -> bytes: 

233 """ 

234 Encrypts and returns a message ``message`` using the secret key ``sk``, 

235 public key ``pk``, and the nonce ``nonce``. 

236 

237 :param message: bytes 

238 :param nonce: bytes 

239 :param pk: bytes 

240 :param sk: bytes 

241 :rtype: bytes 

242 """ 

243 if len(nonce) != crypto_box_NONCEBYTES: 

244 raise exc.ValueError("Invalid nonce size") 

245 

246 if len(pk) != crypto_box_PUBLICKEYBYTES: 

247 raise exc.ValueError("Invalid public key") 

248 

249 if len(sk) != crypto_box_SECRETKEYBYTES: 

250 raise exc.ValueError("Invalid secret key") 

251 

252 _mlen = len(message) 

253 _clen = crypto_box_MACBYTES + _mlen 

254 

255 ciphertext = ffi.new("unsigned char[]", _clen) 

256 

257 rc = lib.crypto_box_easy(ciphertext, message, _mlen, nonce, pk, sk) 

258 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError) 

259 

260 return ffi.buffer(ciphertext, _clen)[:] 

261 

262 

263def crypto_box_open_easy( 

264 ciphertext: bytes, nonce: bytes, pk: bytes, sk: bytes 

265) -> bytes: 

266 """ 

267 Decrypts and returns an encrypted message ``ciphertext``, using the secret 

268 key ``sk``, public key ``pk``, and the nonce ``nonce``. 

269 

270 :param ciphertext: bytes 

271 :param nonce: bytes 

272 :param pk: bytes 

273 :param sk: bytes 

274 :rtype: bytes 

275 """ 

276 if len(nonce) != crypto_box_NONCEBYTES: 

277 raise exc.ValueError("Invalid nonce size") 

278 

279 if len(pk) != crypto_box_PUBLICKEYBYTES: 

280 raise exc.ValueError("Invalid public key") 

281 

282 if len(sk) != crypto_box_SECRETKEYBYTES: 

283 raise exc.ValueError("Invalid secret key") 

284 

285 _clen = len(ciphertext) 

286 

287 ensure( 

288 _clen >= crypto_box_MACBYTES, 

289 f"Input ciphertext must be at least {crypto_box_MACBYTES} long", 

290 raising=exc.TypeError, 

291 ) 

292 

293 _mlen = _clen - crypto_box_MACBYTES 

294 

295 plaintext = ffi.new("unsigned char[]", max(1, _mlen)) 

296 

297 res = lib.crypto_box_open_easy(plaintext, ciphertext, _clen, nonce, pk, sk) 

298 ensure( 

299 res == 0, 

300 "An error occurred trying to decrypt the message", 

301 raising=exc.CryptoError, 

302 ) 

303 

304 return ffi.buffer(plaintext, _mlen)[:] 

305 

306 

307def crypto_box_easy_afternm(message: bytes, nonce: bytes, k: bytes) -> bytes: 

308 """ 

309 Encrypts and returns the message ``message`` using the shared key ``k`` and 

310 the nonce ``nonce``. 

311 

312 :param message: bytes 

313 :param nonce: bytes 

314 :param k: bytes 

315 :rtype: bytes 

316 """ 

317 if len(nonce) != crypto_box_NONCEBYTES: 

318 raise exc.ValueError("Invalid nonce") 

319 

320 if len(k) != crypto_box_BEFORENMBYTES: 

321 raise exc.ValueError("Invalid shared key") 

322 

323 _mlen = len(message) 

324 _clen = crypto_box_MACBYTES + _mlen 

325 

326 ciphertext = ffi.new("unsigned char[]", _clen) 

327 

328 rc = lib.crypto_box_easy_afternm(ciphertext, message, _mlen, nonce, k) 

329 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError) 

330 

331 return ffi.buffer(ciphertext, _clen)[:] 

332 

333 

334def crypto_box_open_easy_afternm( 

335 ciphertext: bytes, nonce: bytes, k: bytes 

336) -> bytes: 

337 """ 

338 Decrypts and returns the encrypted message ``ciphertext``, using the shared 

339 key ``k`` and the nonce ``nonce``. 

340 

341 :param ciphertext: bytes 

342 :param nonce: bytes 

343 :param k: bytes 

344 :rtype: bytes 

345 """ 

346 if len(nonce) != crypto_box_NONCEBYTES: 

347 raise exc.ValueError("Invalid nonce") 

348 

349 if len(k) != crypto_box_BEFORENMBYTES: 

350 raise exc.ValueError("Invalid shared key") 

351 

352 _clen = len(ciphertext) 

353 

354 ensure( 

355 _clen >= crypto_box_MACBYTES, 

356 f"Input ciphertext must be at least {crypto_box_MACBYTES} long", 

357 raising=exc.TypeError, 

358 ) 

359 

360 _mlen = _clen - crypto_box_MACBYTES 

361 

362 plaintext = ffi.new("unsigned char[]", max(1, _mlen)) 

363 

364 res = lib.crypto_box_open_easy_afternm( 

365 plaintext, ciphertext, _clen, nonce, k 

366 ) 

367 ensure( 

368 res == 0, 

369 "An error occurred trying to decrypt the message", 

370 raising=exc.CryptoError, 

371 ) 

372 

373 return ffi.buffer(plaintext, _mlen)[:] 

374 

375 

376def crypto_box_seal(message: bytes, pk: bytes) -> bytes: 

377 """ 

378 Encrypts and returns a message ``message`` using an ephemeral secret key 

379 and the public key ``pk``. 

380 The ephemeral public key, which is embedded in the sealed box, is also 

381 used, in combination with ``pk``, to derive the nonce needed for the 

382 underlying box construct. 

383 

384 :param message: bytes 

385 :param pk: bytes 

386 :rtype: bytes 

387 

388 .. versionadded:: 1.2 

389 """ 

390 ensure( 

391 isinstance(message, bytes), 

392 "input message must be bytes", 

393 raising=TypeError, 

394 ) 

395 

396 ensure( 

397 isinstance(pk, bytes), "public key must be bytes", raising=TypeError 

398 ) 

399 

400 if len(pk) != crypto_box_PUBLICKEYBYTES: 

401 raise exc.ValueError("Invalid public key") 

402 

403 _mlen = len(message) 

404 _clen = crypto_box_SEALBYTES + _mlen 

405 

406 ciphertext = ffi.new("unsigned char[]", _clen) 

407 

408 rc = lib.crypto_box_seal(ciphertext, message, _mlen, pk) 

409 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError) 

410 

411 return ffi.buffer(ciphertext, _clen)[:] 

412 

413 

414def crypto_box_seal_open(ciphertext: bytes, pk: bytes, sk: bytes) -> bytes: 

415 """ 

416 Decrypts and returns an encrypted message ``ciphertext``, using the 

417 recipent's secret key ``sk`` and the sender's ephemeral public key 

418 embedded in the sealed box. The box construct nonce is derived from 

419 the recipient's public key ``pk`` and the sender's public key. 

420 

421 :param ciphertext: bytes 

422 :param pk: bytes 

423 :param sk: bytes 

424 :rtype: bytes 

425 

426 .. versionadded:: 1.2 

427 """ 

428 ensure( 

429 isinstance(ciphertext, bytes), 

430 "input ciphertext must be bytes", 

431 raising=TypeError, 

432 ) 

433 

434 ensure( 

435 isinstance(pk, bytes), "public key must be bytes", raising=TypeError 

436 ) 

437 

438 ensure( 

439 isinstance(sk, bytes), "secret key must be bytes", raising=TypeError 

440 ) 

441 

442 if len(pk) != crypto_box_PUBLICKEYBYTES: 

443 raise exc.ValueError("Invalid public key") 

444 

445 if len(sk) != crypto_box_SECRETKEYBYTES: 

446 raise exc.ValueError("Invalid secret key") 

447 

448 _clen = len(ciphertext) 

449 

450 ensure( 

451 _clen >= crypto_box_SEALBYTES, 

452 (f"Input ciphertext must be at least {crypto_box_SEALBYTES} long"), 

453 raising=exc.TypeError, 

454 ) 

455 

456 _mlen = _clen - crypto_box_SEALBYTES 

457 

458 # zero-length malloc results are implementation.dependent 

459 plaintext = ffi.new("unsigned char[]", max(1, _mlen)) 

460 

461 res = lib.crypto_box_seal_open(plaintext, ciphertext, _clen, pk, sk) 

462 ensure( 

463 res == 0, 

464 "An error occurred trying to decrypt the message", 

465 raising=exc.CryptoError, 

466 ) 

467 

468 return ffi.buffer(plaintext, _mlen)[:]