Brillo开发: 在java代码中实现p224 spake2加密认证

如果想在实现一个Android应用程序的客户端来控制Brillo系统,那么首要问题是解决如何从/privet/v3/auth->@<-中获取access token。当然在此之前,我们还要完成device pairing的操作,在device pairing中的confirm阶段,我们需要从服务器中得到的session id与device commitment中生成client commitment, 而在client commitment创建的时候,我们需要客户端代码能进行p224_spake2 方式的加密、解密操作。网上也找不到关于p224_spake2相关的java代码实现,自己用java实现又不太现实(查看了一下cpp的实现: external/libchrome/crypto/p224_spake.cc,发现自己没那个能力啊)。试试看能不能以JAVA + JNI + native的代码实现。

  • 相关的编译环境:

Brillo项目使用的是brillo-m9-dev分支的代码;Android项目使用的android-5.1.1_r15分支的代码。

NOTE: Android项目不要使用6.0(M)的分支,在6.0下编译出来的JNI库6.0版本以下的系统可能无法使用。

  • 生成静态链接库:libbrokit.a

需要在Brillo项目上生成一个静态库,这个静态库要求:

  1. 包含external/libchrome/crypto/p224_spake.cc
  2. 包含external/libweave/{data_encoding.cc,third_party/{modp_b64/modp_b64.cc,libuweave/sr/crypto_hmac.c},我们在生成client commitment, authorization code的时候,会用到libweave中相关实现。

先看一下如何生成client commitment, authorization code:

bool create_auth_code(std::string password, std::string sessionId, std::string devCmt,
        std::string &cliCmt, std::string &authCode)
{
    crypto::P224EncryptedKeyExchange spake{
        crypto::P224EncryptedKeyExchange::kPeerTypeClient, password};

    cliCmt = weave::Base64Encode(spake.GetNextMessage());

    std::vector<uint8_t> deviceCommitmentDecoded;
    weave::Base64Decode(devCmt, &deviceCommitmentDecoded);

    spake.ProcessMessage(std::string(deviceCommitmentDecoded.begin(),
        deviceCommitmentDecoded.end()));

    const std::string &key = spake.GetUnverifiedKey();
    std::vector<uint8_t> authCodeRaw{
        weave::privet::HmacSha256(std::vector<uint8_t>{key.begin(), key.end()},
            std::vector<uint8_t>{sessionId.begin(), sessionId.end()})};

    authCode = weave::Base64Encode(authCodeRaw);

    return true;
}

可以看到会使用到libweave中的crypto::P224EncryptedKeyExchange, weave::Base64Encode, weave::privet::HmacSha256这些相关的实现。为了尽可能少地改动源代码,这里通过Android.mk(makefile)来实现:

libbr_libchrome.a包含external/libchrome中的相关文件:

LOCAL_PATH := $(call my-dir)

BRPRE := libbro

include $(CLEAR_VARS)

LIBCHROME_PATH := external/libchrome

#LOCAL_RTTI_FLAG := -frtti
LOCAL_CPP_EXTENSION := .cc
LOCAL_CFLAGS := \
	-Wall -Werror \
	-Wno-char-subscripts -Wno-missing-field-initializers \
	-Wno-unused-function -Wno-unused-parameter -fvisibility=hidden

LOCAL_CPPFLAGS := \
	-Wno-deprecated-register -Wno-sign-promo \
	-Wno-non-virtual-dtor

LOCAL_C_INCLUDES := \
	external/gmock/include \
	external/gtest/include \
	external/libchrome

LOCAL_MODULE := $(BRPRE)_libchrome

LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := STATIC_LIBRARIES

libchrome_LOCAL_SRC_FILES := \
	base/at_exit.cc \
	base/callback_internal.cc \
	base/files/file_util_posix.cc \
	base/lazy_instance.cc \
	base/pickle.cc \
	base/rand_util.cc \
	base/rand_util_posix.cc \
	base/strings/string_number_conversions.cc \
	base/strings/string_util.cc \
	base/synchronization/lock_impl_posix.cc \
	base/threading/platform_thread_posix.cc \
	crypto/p224.cc \
	crypto/p224_spake.cc \
	crypto/random.cc \
	crypto/secure_hash_default.cc \
	crypto/secure_util.cc \
	crypto/sha2.cc \
	crypto/third_party/nss/sha512.cc

libchrome_LOCAL_SRC_FILES += \
	base/command_line.cc \
	base/debug/alias.cc \
	base/debug/debugger.cc \
	base/debug/debugger_posix.cc \
	base/files/file_path.cc \
	base/files/file_path_constants.cc \
	base/logging.cc \
	base/strings/string_piece.cc

$(call local-intermediates-dir)/$(LIBCHROME_PATH)/%.cc: PRIV_INTERMEDIATES_DIR := $(call local-intermediates-dir)
$(call local-intermediates-dir)/$(LIBCHROME_PATH)/%.cc: | \
		$(ACP) $(addprefix $(LIBCHROME_PATH)/,$(libchrome_LOCAL_SRC_FILES))
	$(hide)mkdir -p $(dir $@)
	$(hide)$(ACP) $(patsubst $(PRIV_INTERMEDIATES_DIR)/%,%,$@) $@

LOCAL_GENERATED_SOURCES := \
	$(addprefix $(call local-intermediates-dir)/$(LIBCHROME_PATH)/,$(libchrome_LOCAL_SRC_FILES))

include $(BUILD_STATIC_LIBRARY)

libbro_libweave.a包含external/libweave中的相关文件:

include $(CLEAR_VARS)

LIBWEAVE_PATH := external/libweave

#LOCAL_RTTI_FLAG := -frtti
LOCAL_CPP_EXTENSION := .cc
LOCAL_CFLAGS := \
	-Wall -Werror \
	-Wno-char-subscripts -Wno-missing-field-initializers \
	-Wno-unused-function -Wno-unused-parameter -fvisibility=hidden

LOCAL_CPPFLAGS := \
	-Wno-deprecated-register \
	-Wno-sign-compare \
	-Wno-sign-promo \
	-Wno-non-virtual-dtor

LOCAL_C_INCLUDES := \
	external/boringssl/src/include \
	external/libchrome \
	external/libweave \
	external/libweave/third_party/modp_b64/modp_b64 \
	external/libweave/third_party/modp_b64 \
	external/libweave/third_party/libuweave

LOCAL_MODULE := $(BRPRE)_libweave

LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := STATIC_LIBRARIES

libweave_LOCAL_SRC_FILES := \
	src/data_encoding.cc \
	src/privet/openssl_utils.cc \
	third_party/modp_b64/modp_b64.cc \
	third_party/libuweave/src/crypto_hmac.c
	
$(call local-intermediates-dir)/$(LIBWEAVE_PATH)/%.cc: PRIV_INTERMEDIATES_DIR := $(call local-intermediates-dir)
$(call local-intermediates-dir)/$(LIBWEAVE_PATH)/%.cc: | \
		$(ACP) $(addprefix $(LIBWEAVE_PATH)/,$(libweave_LOCAL_SRC_FILES))
	$(hide)mkdir -p $(dir $@)
	$(hide)$(ACP) $(patsubst $(PRIV_INTERMEDIATES_DIR)/%,%,$@) $@

$(call local-intermediates-dir)/$(LIBWEAVE_PATH)/%.c: PRIV_INTERMEDIATES_DIR := $(call local-intermediates-dir)
$(call local-intermediates-dir)/$(LIBWEAVE_PATH)/%.c: | \
		$(ACP) $(addprefix $(LIBWEAVE_PATH)/,$(libweave_LOCAL_SRC_FILES))
	$(hide)mkdir -p $(dir $@)
	$(hide)$(ACP) $(patsubst $(PRIV_INTERMEDIATES_DIR)/%,%,$@) $@

LOCAL_GENERATED_SOURCES := \
	$(addprefix $(call local-intermediates-dir)/$(LIBWEAVE_PATH)/,$(libweave_LOCAL_SRC_FILES))

include $(BUILD_STATIC_LIBRARY)

而libbrokit.a包含的则是libbro_libchrome.a, libbro_libchrome.a, 以及我自己实现的create_auth_code()方法(在文件kit.cc中):

include $(CLEAR_VARS)

#LOCAL_RTTI_FLAG := -frtti
LOCAL_CPP_EXTENSION := .cc
LOCAL_CFLAGS := \
	-Wall -Werror \
	-Wno-char-subscripts -Wno-missing-field-initializers \
	-Wno-unused-function -Wno-unused-parameter -fvisibility=hidden

LOCAL_CPPFLAGS := \
	-Wno-deprecated-register -Wno-sign-promo \
	-Wno-non-virtual-dtor

LOCAL_C_INCLUDES := \
	external/gmock/include \
	external/gtest/include \
	external/libchrome \
	external/libweave

LOCAL_MODULE := $(BRPRE)kit

LOCAL_WHOLE_STATIC_LIBRARIES := \
	$(BRPRE)_libchrome $(BRPRE)_libweave \
	libcrypto_static

LOCAL_SRC_FILES += \
	kit.cc

include $(BUILD_STATIC_LIBRARY)

my_LOCAL_BUILT_MODULE := $(LOCAL_BUILT_MODULE)

$(LOCAL_PATH)/$(notdir $(my_LOCAL_BUILT_MODULE)): $(LOCAL_BUILT_MODULE)
	$(copy-file-to-target)

最后会将libbrokit.a copy到与这个Android.mk同级的目录中。

同时,这里还有一个简单的应用,用于验证生成的libbrokit.a是否存在问题:

include $(CLEAR_VARS)

LOCAL_CPP_EXTENSION := .cc
LOCAL_CFLAGS := \
	-Wall -Werror \
	-Wno-char-subscripts -Wno-missing-field-initializers \
	-Wno-unused-function -Wno-unused-parameter

LOCAL_CPPFLAGS := \
	-Wno-deprecated-register -Wno-sign-promo \
	-Wno-non-virtual-dtor

LOCAL_C_INCLUDES := \
	external/gmock/include \
	external/gtest/include \
	external/libchrome \
	external/libweave

LOCAL_MODULE := Kit

LOCAL_STATIC_LIBRARIES := \
	$(BRPRE)kit

LOCAL_SHARED_LIBRARIES := \
	liblog

LOCAL_SRC_FILES += \
	main.cc

include $(BUILD_EXECUTABLE)

# ----------------------------------------------------------------------------

$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/$(notdir $(my_LOCAL_BUILT_MODULE))

main.cc文件内容如下:

int main(int argc, char *argv[])
{
    std::string sessionId{argv[1]}, devCmt{argv[2]};
    std::string cliCmt, authCode;

    create_auth_code("hello", sessionId, devCmt, cliCmt, authCode);

    return 0;
}
  • 生成动态链接库:libbrodm-jni.so

本来想着已经有完整的静态库了并且它所依赖的动态库只有libc, libc++和liblog,在Brillo项目中随便整一个JNI库应该没有什么问题,考虑到Brillo项目中有libnativehelper文件夹,应该可以在这个项目中编译一个JNI库,于是mma, 报错了!libnativehelper代码编译出错了:

In file included from libnativehelper/AsynchronousCloseMonitor.cpp:19:
libnativehelper/include/nativehelper/AsynchronousCloseMonitor.h:20:10: fatal error: 'ScopedPthreadMutexLock.h' file not found
#include "ScopedPthreadMutexLock.h"
         ^
1 error generated.
ninja: build stopped: subcommand failed.

考虑到brillo-m9-dev可能是开发分支,Brillo系统中没有使用到JAVA或者是JNI的代码,编译出错也正常。于是考虑将android-6.0.0_r5分支的代码checkout,再次编译,果然没有问题。

有了JNI库,我们就可以编译一个Android app运行下,看一下动态库能不能正常加载,相关的方法能不能正常运行。很遗憾,在Brillo项目中编译出来的JNI库不能在android-5.1.1的系统上正常运行,从log上看,加载JNI库就有问题:

W/linker  (12375): libbrodm-jni.so: unused DT entry: type 0x6000000f arg 0xa490
W/linker  (12375): libbrodm-jni.so: unused DT entry: type 0x60000010 arg 0xcb8
W/linker  (12375): libbrodm-jni.so: unused DT entry: type 0x6ffffef5 arg 0x9344
W/linker  (12375): libbrodm-jni.so: unused DT entry: type 0x6ffffffe arg 0xa440
W/linker  (12375): libbrodm-jni.so: unused DT entry: type 0x6fffffff arg 0x2
E/art     (12375): dlopen("/data/app/com.brobwind.brodm-2/lib/arm/libbrodm-jni.so", RTLD_LAZY) failed: dlopen failed: empty/missing DT_HASH in "libbrodm-jni.so" (built with --hash-style=gnu?)
D/AndroidRuntime(12375): Shutting down VM
--------- beginning of crash
E/AndroidRuntime(12375): FATAL EXCEPTION: main
E/AndroidRuntime(12375): Process: com.brobwind.brodm, PID: 12375
E/AndroidRuntime(12375): java.lang.UnsatisfiedLinkError: dlopen failed: empty/missing DT_HASH in "libbrodm-jni.so" (built with --hash-style=gnu?)
E/AndroidRuntime(12375): 	at java.lang.Runtime.loadLibrary(Runtime.java:371)
E/AndroidRuntime(12375): 	at java.lang.System.loadLibrary(System.java:988)
E/

于是只好在android-51.1_r15项目中编译了,可是编译的时候居然出错了:

target SharedLib: libbrodm-jni (out/target/product/mini-emulator-armv7-a-neon/obj/SHARED_LIBRARIES/libbrodm-jni_intermediates/LINKED/libbrodm-jni.so)
bionic/libc/include/stdio.h:398: error: undefined reference to '__fwrite_chk'
bionic/libc/include/stdio.h:398: error: undefined reference to '__fwrite_chk'
bionic/libc/include/stdio.h:398: error: undefined reference to '__fwrite_chk'
bionic/libc/include/string.h:166: error: undefined reference to '__memchr_chk'
bionic/libc/include/string.h:166: error: undefined reference to '__memchr_chk'
collect2: error: ld returned 1 exit status

这两个函数在bionic里面定义,android-5.1.1_15项目中没有定义。

心想android-6.0的代码比较新,应该可以编译通过。果然,再一次编译通过。可是,还是运行不了,同样的问题。

所以 最后才会有了__bionic_patch.cpp这个文件:

extern "C" size_t /*__attribute__((weak))*/ __fwrite_chk(const void * __restrict buf, size_t size, size_t count,
                               FILE * __restrict stream, size_t /*buf_size*/) {
  return fwrite(buf, size, count, stream);
}

extern "C" void* /*__attribute__((weak))*/ __memchr_chk(const void* s, int c, size_t n, size_t /*buf_size*/) {
  return memchr(s, c, n);
}

关于完整的代码,请参考:->@<-

发表评论

电子邮件地址不会被公开。 必填项已用*标注