Introduce a compiler-optimization safe memset() alternative
memset() may be optimized away by the
compiler if zero'ing is considered to
have no side-effects.
This change adds always_memset(), an
implementation that indirects writes via
a volatile pointer and hence survives
optimization.
Tested against x86-64 Clang 3.9.0,
x86-64 Gcc 6.2, ARM64 gcc 4.8, and
ARM gcc 4.8.2.
BRANCH=none
BUG=none
TEST=compilation succeeds
Change-Id: Ib1d3d0c0450bf2c95b3ffcf566a484e1db6a908d
Signed-off-by: nagendra modadugu <ngm@google.com>
Reviewed-on: https://chromium-review.googlesource.com/400467
Commit-Ready: Nagendra Modadugu <ngm@google.com>
Tested-by: Nagendra Modadugu <ngm@google.com>
Reviewed-by: Marius Schilder <mschilder@chromium.org>
Reviewed-by: Andrey Pronin <apronin@chromium.org>
diff --git a/Makefile b/Makefile
index ffc90ce..60319d7 100644
--- a/Makefile
+++ b/Makefile
@@ -10,6 +10,7 @@
SOURCES += p256_prng.c
SOURCES += sha.c
SOURCES += sha256.c
+SOURCES += util.c
# Use V=1 for verbose output
ifeq ($(V),)
diff --git a/hmac.c b/hmac.c
index f920c59..ef6ad82 100644
--- a/hmac.c
+++ b/hmac.c
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cryptoc/hmac.h"
+#include "cryptoc/util.h"
#include <string.h>
#include "cryptoc/sha.h"
@@ -65,6 +66,6 @@
HASH_init(&ctx->hash);
HASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad));
HASH_update(&ctx->hash, digest, HASH_size(&ctx->hash));
- memset(&ctx->opad[0], 0, sizeof(ctx->opad)); // wipe key
+ always_memset(&ctx->opad[0], 0, sizeof(ctx->opad)); // wipe key
return HASH_final(&ctx->hash);
}
diff --git a/include/cryptoc/util.h b/include/cryptoc/util.h
new file mode 100644
index 0000000..4ba7b21
--- /dev/null
+++ b/include/cryptoc/util.h
@@ -0,0 +1,23 @@
+// Copyright 2016 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef SECURITY_UTIL_LITE_UTIL_H_
+#define SECURITY_UTIL_LITE_UTIL_H_
+
+#include <stddef.h>
+
+/* An implementation of memset that ought not to be optimized away;
+ * useful for scrubbing security sensitive buffers. */
+void *always_memset(void *s, int c, size_t n);
+
+#endif // SECURITY_UTIL_LITE_UTIL_H_
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..6f40509
--- /dev/null
+++ b/util.c
@@ -0,0 +1,24 @@
+// Copyright 2016 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "cryptoc/util.h"
+
+static void always_memset_impl(volatile char *s, int c, size_t n) {
+ while (n--)
+ *s++ = c;
+}
+
+void *always_memset(void *s, int c, size_t n) {
+ always_memset_impl(s, c, n);
+ return s;
+}