1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stddef.h>
6 #include <stdint.h>
7 #include <string.h>
8
9 #include <crypto/bytes.h>
10 #include <crypto/secret.h>
11 #include <explicit-memory/bytes.h>
12 #include <fbl/algorithm.h>
13 #include <fbl/macros.h>
14 #include <fbl/unique_ptr.h>
15 #include <lib/fdio/debug.h>
16 #include <zircon/errors.h>
17 #include <zircon/status.h>
18 #include <zircon/syscalls.h>
19 #include <zircon/types.h>
20
21 // See note in //zircon/third_party/ulib/uboringssl/rules.mk
22 #define BORINGSSL_NO_CXX
23 #include <openssl/mem.h>
24
25 #include <utility>
26
27 #define ZXDEBUG 0
28
29 namespace crypto {
30
31 // Public methods
32
Bytes()33 Bytes::Bytes() : buf_(nullptr), len_(0) {}
~Bytes()34 Bytes::~Bytes() {}
35
Randomize(size_t len)36 zx_status_t Bytes::Randomize(size_t len) {
37 zx_status_t status = Resize(len);
38 if (status != ZX_OK) {
39 return status;
40 }
41 zx_cprng_draw(buf_.get(), len);
42 return ZX_OK;
43 }
44
Resize(size_t size,uint8_t fill)45 zx_status_t Bytes::Resize(size_t size, uint8_t fill) {
46 // Early exit if truncating to zero or if size is unchanged
47 if (size == 0) {
48 buf_.reset();
49 len_ = 0;
50 return ZX_OK;
51 }
52 if (size == len_) {
53 return ZX_OK;
54 }
55
56 // Allocate new memory
57 fbl::AllocChecker ac;
58 fbl::unique_ptr<uint8_t[]> tmp(new (&ac) uint8_t[size]);
59 if (!ac.check()) {
60 xprintf("allocation failed: %zu bytes\n", size);
61 return ZX_ERR_NO_MEMORY;
62 }
63
64 // Fill it with old data and pad as needed
65 if (len_ == 0) {
66 memset(tmp.get(), fill, size);
67 } else if (len_ < size) {
68 memcpy(tmp.get(), buf_.get(), len_);
69 memset(tmp.get() + len_, fill, size - len_);
70 } else {
71 memcpy(tmp.get(), buf_.get(), size);
72 }
73
74 len_ = size;
75 buf_ = std::move(tmp);
76 return ZX_OK;
77 }
78
Copy(const void * buf,size_t len,zx_off_t off)79 zx_status_t Bytes::Copy(const void* buf, size_t len, zx_off_t off) {
80 zx_status_t rc;
81
82 if (len == 0) {
83 return ZX_OK;
84 }
85 if (!buf) {
86 xprintf("null buffer\n");
87 return ZX_ERR_INVALID_ARGS;
88 }
89 size_t size;
90 if (add_overflow(off, len, &size)) {
91 xprintf("overflow\n");
92 return ZX_ERR_INVALID_ARGS;
93 }
94
95 if (len_ < size && (rc = Resize(size)) != ZX_OK) {
96 return rc;
97 }
98 memcpy(buf_.get() + off, buf, len);
99
100 return ZX_OK;
101 }
102
operator [](zx_off_t off) const103 const uint8_t& Bytes::operator[](zx_off_t off) const {
104 ZX_ASSERT(off < len_);
105 return buf_[off];
106 }
107
operator [](zx_off_t off)108 uint8_t& Bytes::operator[](zx_off_t off) {
109 ZX_ASSERT(off < len_);
110 return buf_[off];
111 }
112
operator ==(const Bytes & other) const113 bool Bytes::operator==(const Bytes& other) const {
114 if (len_ != other.len_) {
115 return false;
116 } else if (len_ == 0) {
117 return true;
118 } else {
119 ZX_DEBUG_ASSERT(buf_.get());
120 ZX_DEBUG_ASSERT(other.buf_.get());
121 return CRYPTO_memcmp(buf_.get(), other.buf_.get(), len_) == 0;
122 }
123 }
124
125 } // namespace crypto
126