Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/PyNaCl-1.6.0.dev1-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 typing import Tuple 

15 

16from nacl import exceptions as exc 

17from nacl._sodium import ffi, lib 

18from nacl.exceptions import ensure 

19 

20 

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

22 

23 

24crypto_box_SECRETKEYBYTES: int = lib.crypto_box_secretkeybytes() 

25crypto_box_PUBLICKEYBYTES: int = lib.crypto_box_publickeybytes() 

26crypto_box_SEEDBYTES: int = lib.crypto_box_seedbytes() 

27crypto_box_NONCEBYTES: int = lib.crypto_box_noncebytes() 

28crypto_box_ZEROBYTES: int = lib.crypto_box_zerobytes() 

29crypto_box_BOXZEROBYTES: int = lib.crypto_box_boxzerobytes() 

30crypto_box_BEFORENMBYTES: int = lib.crypto_box_beforenmbytes() 

31crypto_box_SEALBYTES: int = lib.crypto_box_sealbytes() 

32crypto_box_MACBYTES: int = lib.crypto_box_macbytes() 

33 

34 

35def crypto_box_keypair() -> Tuple[bytes, bytes]: 

36 """ 

37 Returns a randomly generated public and secret key. 

38 

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

40 """ 

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

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

43 

44 rc = lib.crypto_box_keypair(pk, sk) 

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

46 

47 return ( 

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

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

50 ) 

51 

52 

53def crypto_box_seed_keypair(seed: bytes) -> Tuple[bytes, bytes]: 

54 """ 

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

56 from an input ``seed``. 

57 

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

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

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

61 

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

63 Anyone who knows the seed is really in possession of 

64 the corresponding PrivateKey. 

65 

66 

67 :param seed: bytes 

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

69 """ 

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

71 

72 if len(seed) != crypto_box_SEEDBYTES: 

73 raise exc.ValueError("Invalid seed") 

74 

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

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

77 

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

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

80 

81 return ( 

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

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

84 ) 

85 

86 

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

88 """ 

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

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

91 

92 :param message: bytes 

93 :param nonce: bytes 

94 :param pk: bytes 

95 :param sk: bytes 

96 :rtype: bytes 

97 """ 

98 if len(nonce) != crypto_box_NONCEBYTES: 

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

100 

101 if len(pk) != crypto_box_PUBLICKEYBYTES: 

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

103 

104 if len(sk) != crypto_box_SECRETKEYBYTES: 

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

106 

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

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

109 

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

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

112 

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

114 

115 

116def crypto_box_open( 

117 ciphertext: bytes, nonce: bytes, pk: bytes, sk: bytes 

118) -> bytes: 

119 """ 

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

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

122 

123 :param ciphertext: bytes 

124 :param nonce: bytes 

125 :param pk: bytes 

126 :param sk: bytes 

127 :rtype: bytes 

128 """ 

129 if len(nonce) != crypto_box_NONCEBYTES: 

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

131 

132 if len(pk) != crypto_box_PUBLICKEYBYTES: 

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

134 

135 if len(sk) != crypto_box_SECRETKEYBYTES: 

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

137 

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

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

140 

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

142 ensure( 

143 res == 0, 

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

145 raising=exc.CryptoError, 

146 ) 

147 

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

149 

150 

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

152 """ 

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

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

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

156 

157 :param pk: bytes 

158 :param sk: bytes 

159 :rtype: bytes 

160 """ 

161 if len(pk) != crypto_box_PUBLICKEYBYTES: 

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

163 

164 if len(sk) != crypto_box_SECRETKEYBYTES: 

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

166 

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

168 

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

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

171 

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

173 

174 

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

176 """ 

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

178 the nonce ``nonce``. 

179 

180 :param message: bytes 

181 :param nonce: bytes 

182 :param k: bytes 

183 :rtype: bytes 

184 """ 

185 if len(nonce) != crypto_box_NONCEBYTES: 

186 raise exc.ValueError("Invalid nonce") 

187 

188 if len(k) != crypto_box_BEFORENMBYTES: 

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

190 

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

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

193 

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

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

196 

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

198 

199 

200def crypto_box_open_afternm( 

201 ciphertext: bytes, nonce: bytes, k: bytes 

202) -> bytes: 

203 """ 

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

205 key ``k`` and the nonce ``nonce``. 

206 

207 :param ciphertext: bytes 

208 :param nonce: bytes 

209 :param k: bytes 

210 :rtype: bytes 

211 """ 

212 if len(nonce) != crypto_box_NONCEBYTES: 

213 raise exc.ValueError("Invalid nonce") 

214 

215 if len(k) != crypto_box_BEFORENMBYTES: 

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

217 

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

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

220 

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

222 ensure( 

223 res == 0, 

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

225 raising=exc.CryptoError, 

226 ) 

227 

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

229 

230 

231def crypto_box_easy( 

232 message: bytes, nonce: bytes, pk: bytes, sk: bytes 

233) -> bytes: 

234 """ 

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

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

237 

238 :param message: bytes 

239 :param nonce: bytes 

240 :param pk: bytes 

241 :param sk: bytes 

242 :rtype: bytes 

243 """ 

244 if len(nonce) != crypto_box_NONCEBYTES: 

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

246 

247 if len(pk) != crypto_box_PUBLICKEYBYTES: 

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

249 

250 if len(sk) != crypto_box_SECRETKEYBYTES: 

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

252 

253 _mlen = len(message) 

254 _clen = crypto_box_MACBYTES + _mlen 

255 

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

257 

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

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

260 

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

262 

263 

264def crypto_box_open_easy( 

265 ciphertext: bytes, nonce: bytes, pk: bytes, sk: bytes 

266) -> bytes: 

267 """ 

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

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

270 

271 :param ciphertext: bytes 

272 :param nonce: bytes 

273 :param pk: bytes 

274 :param sk: bytes 

275 :rtype: bytes 

276 """ 

277 if len(nonce) != crypto_box_NONCEBYTES: 

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

279 

280 if len(pk) != crypto_box_PUBLICKEYBYTES: 

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

282 

283 if len(sk) != crypto_box_SECRETKEYBYTES: 

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

285 

286 _clen = len(ciphertext) 

287 

288 ensure( 

289 _clen >= crypto_box_MACBYTES, 

290 "Input ciphertext must be at least {} long".format( 

291 crypto_box_MACBYTES 

292 ), 

293 raising=exc.TypeError, 

294 ) 

295 

296 _mlen = _clen - crypto_box_MACBYTES 

297 

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

299 

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

301 ensure( 

302 res == 0, 

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

304 raising=exc.CryptoError, 

305 ) 

306 

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

308 

309 

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

311 """ 

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

313 the nonce ``nonce``. 

314 

315 :param message: bytes 

316 :param nonce: bytes 

317 :param k: bytes 

318 :rtype: bytes 

319 """ 

320 if len(nonce) != crypto_box_NONCEBYTES: 

321 raise exc.ValueError("Invalid nonce") 

322 

323 if len(k) != crypto_box_BEFORENMBYTES: 

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

325 

326 _mlen = len(message) 

327 _clen = crypto_box_MACBYTES + _mlen 

328 

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

330 

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

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

333 

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

335 

336 

337def crypto_box_open_easy_afternm( 

338 ciphertext: bytes, nonce: bytes, k: bytes 

339) -> bytes: 

340 """ 

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

342 key ``k`` and the nonce ``nonce``. 

343 

344 :param ciphertext: bytes 

345 :param nonce: bytes 

346 :param k: bytes 

347 :rtype: bytes 

348 """ 

349 if len(nonce) != crypto_box_NONCEBYTES: 

350 raise exc.ValueError("Invalid nonce") 

351 

352 if len(k) != crypto_box_BEFORENMBYTES: 

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

354 

355 _clen = len(ciphertext) 

356 

357 ensure( 

358 _clen >= crypto_box_MACBYTES, 

359 "Input ciphertext must be at least {} long".format( 

360 crypto_box_MACBYTES 

361 ), 

362 raising=exc.TypeError, 

363 ) 

364 

365 _mlen = _clen - crypto_box_MACBYTES 

366 

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

368 

369 res = lib.crypto_box_open_easy_afternm( 

370 plaintext, ciphertext, _clen, nonce, k 

371 ) 

372 ensure( 

373 res == 0, 

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

375 raising=exc.CryptoError, 

376 ) 

377 

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

379 

380 

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

382 """ 

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

384 and the public key ``pk``. 

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

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

387 underlying box construct. 

388 

389 :param message: bytes 

390 :param pk: bytes 

391 :rtype: bytes 

392 

393 .. versionadded:: 1.2 

394 """ 

395 ensure( 

396 isinstance(message, bytes), 

397 "input message must be bytes", 

398 raising=TypeError, 

399 ) 

400 

401 ensure( 

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

403 ) 

404 

405 if len(pk) != crypto_box_PUBLICKEYBYTES: 

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

407 

408 _mlen = len(message) 

409 _clen = crypto_box_SEALBYTES + _mlen 

410 

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

412 

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

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

415 

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

417 

418 

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

420 """ 

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

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

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

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

425 

426 :param ciphertext: bytes 

427 :param pk: bytes 

428 :param sk: bytes 

429 :rtype: bytes 

430 

431 .. versionadded:: 1.2 

432 """ 

433 ensure( 

434 isinstance(ciphertext, bytes), 

435 "input ciphertext must be bytes", 

436 raising=TypeError, 

437 ) 

438 

439 ensure( 

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

441 ) 

442 

443 ensure( 

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

445 ) 

446 

447 if len(pk) != crypto_box_PUBLICKEYBYTES: 

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

449 

450 if len(sk) != crypto_box_SECRETKEYBYTES: 

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

452 

453 _clen = len(ciphertext) 

454 

455 ensure( 

456 _clen >= crypto_box_SEALBYTES, 

457 ("Input ciphertext must be at least {} long").format( 

458 crypto_box_SEALBYTES 

459 ), 

460 raising=exc.TypeError, 

461 ) 

462 

463 _mlen = _clen - crypto_box_SEALBYTES 

464 

465 # zero-length malloc results are implementation.dependent 

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

467 

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

469 ensure( 

470 res == 0, 

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

472 raising=exc.CryptoError, 

473 ) 

474 

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