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