end-to-end email demo working w/o scroll support
This commit is contained in:
parent
6ee66e847c
commit
a4d24551d5
4 changed files with 276 additions and 49 deletions
189
demo/fw/include/platform/endian.h
Normal file
189
demo/fw/include/platform/endian.h
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2002 Thomas Moestl <tmm@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
/*
|
||||
* Portions copyright (c) 2018, ARM Limited and Contributors.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef ENDIAN_H
|
||||
#define ENDIAN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* General byte order swapping functions.
|
||||
*/
|
||||
#define bswap16(x) __bswap16(x)
|
||||
#define bswap32(x) __bswap32(x)
|
||||
#define bswap64(x) __bswap64(x)
|
||||
|
||||
/*
|
||||
* Host to big endian, host to little endian, big endian to host, and little
|
||||
* endian to host byte order functions as detailed in byteorder(9).
|
||||
*/
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define htobe16(x) bswap16((x))
|
||||
#define htobe32(x) bswap32((x))
|
||||
#define htobe64(x) bswap64((x))
|
||||
#define htole16(x) ((uint16_t)(x))
|
||||
#define htole32(x) ((uint32_t)(x))
|
||||
#define htole64(x) ((uint64_t)(x))
|
||||
|
||||
#define be16toh(x) bswap16((x))
|
||||
#define be32toh(x) bswap32((x))
|
||||
#define be64toh(x) bswap64((x))
|
||||
#define le16toh(x) ((uint16_t)(x))
|
||||
#define le32toh(x) ((uint32_t)(x))
|
||||
#define le64toh(x) ((uint64_t)(x))
|
||||
#else /* __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ */
|
||||
#define htobe16(x) ((uint16_t)(x))
|
||||
#define htobe32(x) ((uint32_t)(x))
|
||||
#define htobe64(x) ((uint64_t)(x))
|
||||
#define htole16(x) bswap16((x))
|
||||
#define htole32(x) bswap32((x))
|
||||
#define htole64(x) bswap64((x))
|
||||
|
||||
#define be16toh(x) ((uint16_t)(x))
|
||||
#define be32toh(x) ((uint32_t)(x))
|
||||
#define be64toh(x) ((uint64_t)(x))
|
||||
#define le16toh(x) bswap16((x))
|
||||
#define le32toh(x) bswap32((x))
|
||||
#define le64toh(x) bswap64((x))
|
||||
#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
|
||||
|
||||
/* Alignment-agnostic encode/decode bytestream to/from little/big endian. */
|
||||
|
||||
static __inline uint16_t
|
||||
be16dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return ((p[0] << 8) | p[1]);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
be32dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
be64dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4));
|
||||
}
|
||||
|
||||
static __inline uint16_t
|
||||
le16dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return ((p[1] << 8) | p[0]);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
le32dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
le64dec(const void *pp)
|
||||
{
|
||||
uint8_t const *p = (uint8_t const *)pp;
|
||||
|
||||
return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
be16enc(void *pp, uint16_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = (u >> 8) & 0xff;
|
||||
p[1] = u & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
be32enc(void *pp, uint32_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = (u >> 24) & 0xff;
|
||||
p[1] = (u >> 16) & 0xff;
|
||||
p[2] = (u >> 8) & 0xff;
|
||||
p[3] = u & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
be64enc(void *pp, uint64_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
be32enc(p, (uint32_t)(u >> 32));
|
||||
be32enc(p + 4, (uint32_t)(u & 0xffffffffU));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
le16enc(void *pp, uint16_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = u & 0xff;
|
||||
p[1] = (u >> 8) & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
le32enc(void *pp, uint32_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
p[0] = u & 0xff;
|
||||
p[1] = (u >> 8) & 0xff;
|
||||
p[2] = (u >> 16) & 0xff;
|
||||
p[3] = (u >> 24) & 0xff;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
le64enc(void *pp, uint64_t u)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)pp;
|
||||
|
||||
le32enc(p, (uint32_t)(u & 0xffffffffU));
|
||||
le32enc(p + 4, (uint32_t)(u >> 32));
|
||||
}
|
||||
|
||||
#endif /* ENDIAN_H */
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
do { \
|
||||
int mbedtls_rc = fun_call; \
|
||||
if (mbedtls_rc) { \
|
||||
LOG_PRINTF("Error: " #fun_call ": " msg ": rc=-0x%x\n", __VA_ARGS__ -mbedtls_rc); \
|
||||
LOG_PRINTF("Error: " #fun_call ": " msg ": rc=-0x%x\r\n", __VA_ARGS__ -mbedtls_rc); \
|
||||
err = err_value; \
|
||||
goto cleanup; \
|
||||
} \
|
||||
|
|
@ -112,11 +112,11 @@ enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t bufl
|
|||
enum ca_error err = CA_ERR_CORRUPTED_STATE;
|
||||
|
||||
if (buflen <= 0) {
|
||||
LOG_PRINTF("Error: parse_age_buf: (buflen == %d) <= 0\n", buflen);
|
||||
LOG_PRINTF("Error: parse_age_buf: (buflen == %d) <= 0\r\n", buflen);
|
||||
return CA_ERR_INVALID_HEADER;
|
||||
}
|
||||
if (strnlen(buf, buflen) >= buflen) {
|
||||
LOG_PRINTF("Error: parse_age_buf: Buffer is not null-terminated\n");
|
||||
LOG_PRINTF("Error: parse_age_buf: Buffer is not null-terminated\r\n");
|
||||
return CA_ERR_INVALID_HEADER; /* buffer is not null-terminated */
|
||||
}
|
||||
|
||||
|
|
@ -124,13 +124,13 @@ enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t bufl
|
|||
const char *line_end = strchr(buf, '\n');
|
||||
|
||||
if (!line_end) {
|
||||
LOG_PRINTF("Error: parse_age_buf: newline in header not found\n");
|
||||
LOG_PRINTF("Error: parse_age_buf: newline in header not found\r\n");
|
||||
return CA_ERR_INVALID_HEADER; /* header has to contain at least magic string, one stanza and payload separator line */
|
||||
}
|
||||
|
||||
const char *header_start = "age-encryption.org/v";
|
||||
if (strncmp(current_line, header_start, strlen(header_start))) {
|
||||
LOG_PRINTF("Error: parse_age_buf: header magic string corrupt or missing\n");
|
||||
LOG_PRINTF("Error: parse_age_buf: header magic string corrupt or missing\r\n");
|
||||
return CA_ERR_INVALID_HEADER; /* header magic string corrupt or missing */
|
||||
}
|
||||
|
||||
|
|
@ -138,12 +138,12 @@ enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t bufl
|
|||
unsigned long header_version = strtoul(current_line + strlen(header_start), &endptr, 10);
|
||||
|
||||
if (current_line[strlen(header_start)] == '\0' || header_version == ULONG_MAX || *endptr != '\n') {
|
||||
LOG_PRINTF("Error: parse_age_buf: corrupt version number\n");
|
||||
LOG_PRINTF("Error: parse_age_buf: corrupt version number\r\n");
|
||||
return CA_ERR_INVALID_HEADER; /* corrupt version number */
|
||||
}
|
||||
|
||||
if (header_version > 1) {
|
||||
LOG_PRINTF("Error: parse_age_buf: file version too new\n");
|
||||
LOG_PRINTF("Error: parse_age_buf: file version too new\r\n");
|
||||
return CA_ERR_FILE_FORMAT_TOO_NEW;
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +155,7 @@ enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t bufl
|
|||
|
||||
line_end = strchr(current_line, '\n');
|
||||
if (!line_end) {
|
||||
LOG_PRINTF("Error: parse_age_buf: header does not end in newline\n");
|
||||
LOG_PRINTF("Error: parse_age_buf: header does not end in newline\r\n");
|
||||
return CA_ERR_INVALID_HEADER; /* the header must always end with '\n' after the --- separator line */
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t bufl
|
|||
*/
|
||||
}
|
||||
} else {
|
||||
LOG_PRINTF("Error: parse_age_buf: header does not contain any stanzas\n");
|
||||
LOG_PRINTF("Error: parse_age_buf: header does not contain any stanzas\r\n");
|
||||
return CA_ERR_INVALID_HEADER; /* the header must contain at least one stanza */
|
||||
}
|
||||
|
||||
|
|
@ -214,7 +214,7 @@ enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t bufl
|
|||
} else { /* b64 stanza content */
|
||||
|
||||
if (line_end - current_line > 64) {
|
||||
LOG_PRINTF("Error: parse_age_buf: base64 stanza body wider than 64 chars\n");
|
||||
LOG_PRINTF("Error: parse_age_buf: base64 stanza body wider than 64 chars\r\n");
|
||||
return CA_ERR_INVALID_HEADER; /* b64 must be wrapped to exactly 64 chars */
|
||||
}
|
||||
}
|
||||
|
|
@ -236,7 +236,7 @@ enum ca_error parse_stanza(struct ca_keystore *ks, const char *stanza_head, size
|
|||
|
||||
char *line_end = strchr(stanza_head, '\n');
|
||||
if (!line_end) {
|
||||
LOG_PRINTF("Error: parse_stanza: end of line not found (bug, should not happen!)\n");
|
||||
LOG_PRINTF("Error: parse_stanza: end of line not found (bug, should not happen!)\r\n");
|
||||
return CA_ERR_CORRUPTED_STATE;
|
||||
}
|
||||
|
||||
|
|
@ -244,7 +244,7 @@ enum ca_error parse_stanza(struct ca_keystore *ks, const char *stanza_head, size
|
|||
|
||||
const char **stanza_args = calloc(head_len, sizeof(char *));
|
||||
if (!stanza_args) {
|
||||
LOG_PRINTF("Error: parse_stanza: cannot allocate stanza arg memory\n");
|
||||
LOG_PRINTF("Error: parse_stanza: cannot allocate stanza arg memory\r\n");
|
||||
return CA_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
|
|
@ -252,7 +252,7 @@ enum ca_error parse_stanza(struct ca_keystore *ks, const char *stanza_head, size
|
|||
unsigned char *payload = malloc(max_payload_len);
|
||||
if (!payload) {
|
||||
free(stanza_args);
|
||||
LOG_PRINTF("Error: parse_stanza: cannot allocate stanza body memory\n");
|
||||
LOG_PRINTF("Error: parse_stanza: cannot allocate stanza body memory\r\n");
|
||||
return CA_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
|
|
@ -270,7 +270,7 @@ enum ca_error parse_stanza(struct ca_keystore *ks, const char *stanza_head, size
|
|||
if (head_len + 1 < len) { /* has payload */
|
||||
const char *endp = base64_decode(payload, max_payload_len, &b64_len, line_end + 1, len - head_len - 1);
|
||||
if (!endp || endp != stanza_head + len - 1) {
|
||||
LOG_PRINTF("Error: parse_stanza: cannot parse stanza body base64\n");
|
||||
LOG_PRINTF("Error: parse_stanza: cannot parse stanza body base64\r\n");
|
||||
err = CA_ERR_BROKEN_BASE64;
|
||||
goto errout;
|
||||
}
|
||||
|
|
@ -291,7 +291,7 @@ enum ca_error parse_stanza_x25519(struct ca_keystore *ks, size_t nargs, const ch
|
|||
|
||||
/* body length: 16 bytes ciphertext of 128 bit file key + 16 bytes Poly1305 tag */
|
||||
if (nargs != 1 || body_len != 32) {
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: (nargs == %zu) != 1 || (body_len == %zu) != 32\n", nargs, body_len);
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: (nargs == %zu) != 1 || (body_len == %zu) != 32\r\n", nargs, body_len);
|
||||
return CA_ERR_INVALID_HEADER_ARG;
|
||||
}
|
||||
|
||||
|
|
@ -299,18 +299,18 @@ enum ca_error parse_stanza_x25519(struct ca_keystore *ks, size_t nargs, const ch
|
|||
unsigned char ecp_ciphertext[32];
|
||||
const char *arg_newline = strchr(args[0], '\n');
|
||||
if (!arg_newline) {
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: First argument does not end in '\\n' (this is a bug!)\n");
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: First argument does not end in '\\n' (this is a bug!)\r\n");
|
||||
return CA_ERR_CORRUPTED_STATE;
|
||||
}
|
||||
size_t arglen = arg_newline - args[0];
|
||||
const char *endp = base64_decode(ecp_ciphertext, sizeof(ecp_ciphertext), &ciphertext_len, args[0], arglen);
|
||||
if (!endp || endp != arg_newline) {
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: Cannot decode ciphertext header arg base64 %p %p\n", endp, arg_newline);
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: Cannot decode ciphertext header arg base64 %p %p\r\n", endp, arg_newline);
|
||||
return CA_ERR_INVALID_HEADER_ARG;
|
||||
}
|
||||
|
||||
if (ciphertext_len != 32) {
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: Ciphertext header arg has wrong length\n");
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: Ciphertext header arg has wrong length\r\n");
|
||||
return CA_ERR_INVALID_HEADER_ARG;
|
||||
}
|
||||
|
||||
|
|
@ -358,14 +358,14 @@ enum ca_error parse_stanza_x25519(struct ca_keystore *ks, size_t nargs, const ch
|
|||
*/
|
||||
|
||||
if (ecp_plaintext_len != 32) {
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: (ecp_plaintext_len == %d) != 32 (bug, should not happen!)\n", ecp_plaintext_len);
|
||||
LOG_PRINTF("Error: parse_stanza_x25519: (ecp_plaintext_len == %d) != 32 (bug, should not happen!)\r\n", ecp_plaintext_len);
|
||||
err = CA_ERR_CORRUPTED_STATE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
const mbedtls_md_info_t *sha256_md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
if (!sha256_md) {
|
||||
LOG_PRINTF("Error: mbedtls_md_info_from_type: cannot load SHA256\n");
|
||||
LOG_PRINTF("Error: mbedtls_md_info_from_type: cannot load SHA256\r\n");
|
||||
err = CA_ERR_MBEDTLS_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -376,7 +376,7 @@ enum ca_error parse_stanza_x25519(struct ca_keystore *ks, size_t nargs, const ch
|
|||
MBEDTLS_CHECK( mbedtls_ecp_point_write_binary(&x25519_grp, &(ks->x25519_kp.Q),
|
||||
MBEDTLS_ECP_PF_UNCOMPRESSED, &pbin_olen, salt+32, 32) );
|
||||
if (pbin_olen != 32) {
|
||||
LOG_PRINTF("Error: mbedtls_ecp_point_write_binary returned invalid output len: %d != 32\n", pbin_olen);
|
||||
LOG_PRINTF("Error: mbedtls_ecp_point_write_binary returned invalid output len: %d != 32\r\n", pbin_olen);
|
||||
err = CA_ERR_CORRUPTED_STATE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
|
@ -425,7 +425,7 @@ enum ca_error check_file_key(const unsigned char *buf, size_t buflen, const unsi
|
|||
|
||||
const mbedtls_md_info_t *sha256_md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
if (!sha256_md) {
|
||||
LOG_PRINTF("Error: mbedtls_md_info_from_type: cannot load SHA256\n");
|
||||
LOG_PRINTF("Error: mbedtls_md_info_from_type: cannot load SHA256\r\n");
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
|
|
@ -452,12 +452,12 @@ enum ca_error check_file_key(const unsigned char *buf, size_t buflen, const unsi
|
|||
size_t mac_osize = 0;
|
||||
const char *endp = base64_decode(mac, sizeof(mac), &mac_osize, (const char *)found + 1 /* for " " */, buflen - ((const unsigned char *)found - buf));
|
||||
if (!endp || *endp != '\n') {
|
||||
LOG_PRINTF("Error: check_file_key: Cannot decode ciphertext header arg base64\n");
|
||||
LOG_PRINTF("Error: check_file_key: Cannot decode ciphertext header arg base64\r\n");
|
||||
return CA_ERR_INVALID_HEADER_ARG;
|
||||
}
|
||||
|
||||
if (mac_osize != 32) {
|
||||
LOG_PRINTF("Error: check_file_key: (mac_osize == %d) != 32\n", mac_osize);
|
||||
LOG_PRINTF("Error: check_file_key: (mac_osize == %d) != 32\r\n", mac_osize);
|
||||
return CA_ERR_INVALID_HEADER;
|
||||
}
|
||||
|
||||
|
|
@ -500,7 +500,7 @@ enum ca_error stream_decrypt(unsigned char *out, size_t outlen, size_t *out_writ
|
|||
size_t aead_tagsize = 16;
|
||||
|
||||
if (outlen < stream_bytes - aead_tagsize * stream_blocks) {
|
||||
LOG_PRINTF("Error: stream_decrypt: caller-provided buffer too small for decryption result: %zu < %zu\n", outlen, stream_bytes - aead_tagsize * stream_blocks);
|
||||
LOG_PRINTF("Error: stream_decrypt: caller-provided buffer too small for decryption result: %zu < %zu\r\n", outlen, stream_bytes - aead_tagsize * stream_blocks);
|
||||
return CA_ERR_NOT_ENOUGH_SPACE;
|
||||
}
|
||||
|
||||
|
|
@ -517,7 +517,7 @@ enum ca_error stream_decrypt(unsigned char *out, size_t outlen, size_t *out_writ
|
|||
|
||||
const mbedtls_md_info_t *sha256_md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
if (!sha256_md) {
|
||||
LOG_PRINTF("Error: mbedtls_md_info_from_type: cannot load SHA256 MD info\n");
|
||||
LOG_PRINTF("Error: mbedtls_md_info_from_type: cannot load SHA256 MD info\r\n");
|
||||
return CA_ERR_MBEDTLS_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -402,8 +402,18 @@ int main(void)
|
|||
dec_buf[decrypted_size-1] = '\0'; /* overwrite trailing \n */
|
||||
con_printf_blocking("decrypted payload: %s\r\n", dec_buf);
|
||||
|
||||
spif_printf(&spif, "\033[H\033[0m\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\033[H");
|
||||
spif_printf(&spif, "\033[1;92mDecrypted data:\033[0m\n\n%s\n", dec_buf);
|
||||
spif_printf(&spif, "\033[H\033[1;40;32m[tachibana/age decrypted message]\n\033[0;107;30m \n", dec_buf);
|
||||
char *p = dec_buf;
|
||||
char *endl = __strchrnul(dec_buf, '\n');
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
done = *endl == '\0';
|
||||
*endl = '\0';
|
||||
spif_printf(&spif, " %s\n", p);
|
||||
p = endl + 1;
|
||||
endl = __strchrnul(p, '\n');
|
||||
}
|
||||
spif_printf(&spif, " \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n", dec_buf);
|
||||
|
||||
//for (int j=0; j<1000000; j++) {
|
||||
/* pass */
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@ import math
|
|||
import subprocess
|
||||
from email.message import EmailMessage
|
||||
from email.utils import make_msgid
|
||||
import smtplib
|
||||
import textwrap
|
||||
import io
|
||||
import binascii
|
||||
import base64
|
||||
|
||||
import click
|
||||
import bdfparser
|
||||
|
|
@ -27,31 +29,42 @@ def age_encrypt(content, keys):
|
|||
input=content.encode('utf-8'))
|
||||
return proc.stdout
|
||||
|
||||
BORDER_COLOR = '#000000'
|
||||
BACKGROUND_COLOR = '#d61ca1'
|
||||
FONT_FG_COLOR = '#e1e31b'
|
||||
def pack_html(payload_img_cid, hint_img_cid):
|
||||
def data_url(data):
|
||||
return f'data:image/png;base64,{base64.b64encode(data).decode("utf-8")}'
|
||||
|
||||
BORDER_COLOR = '#000000'
|
||||
BACKGROUND_COLOR = '#d020a0'
|
||||
FONT_FG_COLOR = '#e0e010'
|
||||
|
||||
def pack_html(payload_img_cid, hint_img_data):
|
||||
return textwrap.dedent(f'''\
|
||||
<html style="margin: 0; padding: 0; border: 0; width: 100%; height: 100%">
|
||||
<body style="border-style: solid; border-width: 1px; border-color: {BORDER_COLOR}; margin: 0; padding: 0; \
|
||||
background-color: {BACKGROUND_COLOR); width: calc(100% - 4px); height: calc(100% - 4px); overflow: hidden">
|
||||
<body style="border-style: solid; border-width: 2px; border-color: {BORDER_COLOR}; margin: 0; padding: 0; \
|
||||
background-color: {BACKGROUND_COLOR}; background-image: url({data_url(hint_img_data)}); \
|
||||
width: calc(100% - 4px); height: calc(100% - 4px); overflow: hidden">
|
||||
<img src="cid:{payload_img_cid}" style="margin: 0; padding: 0"/>
|
||||
<br/>
|
||||
<img src="cid:{hint_img_cid}" style="margin: 0; padding: 0"/>
|
||||
</body>
|
||||
</html>
|
||||
''').strip()
|
||||
|
||||
def create_hint_img(text, max_w=200, fgcolor=FONT_FG_COLOR, bgcolor=BACKGROUND_COLOR):
|
||||
def create_hint_img(text, max_w=200, fgcolor=FONT_FG_COLOR, bgcolor=BACKGROUND_COLOR, border=10):
|
||||
relative_path = (Path(__file__).parent / '../../../upstream/terminus-font-4.49.1/ter-u16b.bdf').resolve()
|
||||
font_file = os.getenv('HINT_FONT', str(relative_path))
|
||||
font = bdfparser.Font(font_file)
|
||||
hex_to_np = lambda s: np.frombuffer(binascii.unhexlify(s.lstrip('#')), dtype=np.uint8)
|
||||
colors = np.array([hex_to_np(bgcolor), hex_to_np(fgcolor)])
|
||||
|
||||
img = font.draw(text, linelimit=max_w)
|
||||
return Image.fromarray(colors[img.todata(2)])
|
||||
imgs = []
|
||||
for line in text.splitlines():
|
||||
img = colors[np.array(font.draw(line, linelimit=max_w).todata(2))]
|
||||
bg = np.tile(colors[np.newaxis, np.newaxis, 0], (img.shape[0], max_w, 1))
|
||||
w = img.shape[1]
|
||||
bg[:, (max_w-w)//2 : (max_w-w)//2 + w, :] = img
|
||||
imgs.append(bg)
|
||||
img = np.vstack(imgs)
|
||||
bg = np.tile(colors[np.newaxis, np.newaxis, 0], (img.shape[0]+2*border, img.shape[1]+2*border, 1))
|
||||
bg[border:-border, border:-border, :] = img
|
||||
return Image.fromarray(bg)
|
||||
|
||||
# because inexplicably, pillow doesn't have this already
|
||||
def img_to_bytes(img, fmt='png'):
|
||||
|
|
@ -62,13 +75,17 @@ def img_to_bytes(img, fmt='png'):
|
|||
|
||||
@click.command()
|
||||
@click.option('-f', '--from', 'sender')
|
||||
@click.option('-t', '--to', 'recipients')
|
||||
@click.option('-c', '--cc', 'cc')
|
||||
@click.option('-b', '--bcc', 'bcc')
|
||||
@click.option('-t', '--to', 'recipients', multiple=True)
|
||||
@click.option('-c', '--cc', 'cc', multiple=True)
|
||||
@click.option('-b', '--bcc', 'bcc', multiple=True)
|
||||
@click.option('--smtp-server')
|
||||
@click.option('--smtp-user')
|
||||
@click.option('--smtp-password')
|
||||
@click.option('--smtp-port', type=int, default=465)
|
||||
@click.option('-k', '--key', 'keys', multiple=True, required=True)
|
||||
@click.option('-s', '--subject', default='tachibana/age encrypted message')
|
||||
@click.argument('content', type=click.File('r'))
|
||||
def create_age_email(content, sender, recipients, cc, bcc, keys, subject):
|
||||
def create_age_email(content, sender, recipients, cc, bcc, keys, subject, smtp_server, smtp_port, smtp_user, smtp_password):
|
||||
|
||||
encrypted = age_encrypt(content.read(), keys)
|
||||
|
||||
|
|
@ -83,21 +100,32 @@ def create_age_email(content, sender, recipients, cc, bcc, keys, subject):
|
|||
if bcc:
|
||||
msg['Bcc'] = ', '.join(bcc)
|
||||
|
||||
payload_img_cid, hint_img_cid = make_msgid(), make_msgid()
|
||||
hint_img_data = img_to_bytes(create_hint_img('tachibana/age\nencrypted email', max_w=200))
|
||||
|
||||
payload_img_cid = make_msgid()
|
||||
# remove <...> angle brackets from cids in <img> tags
|
||||
msg.set_content(pack_html(payload_img_cid[1:-1], hint_img_cid[1:-1]), subtype='html')
|
||||
msg.set_content(pack_html(payload_img_cid[1:-1], hint_img_data), subtype='html')
|
||||
|
||||
w = max(200, math.ceil(math.sqrt(len(encrypted))))
|
||||
h = math.ceil((len(encrypted) + 64) / w)
|
||||
img_bytes = img_to_bytes(tb_data_encoder.data_encode(encrypted, w, h))
|
||||
msg.add_related(img_bytes, 'image', 'png', cid=payload_img_cid)
|
||||
|
||||
img_bytes = img_to_bytes(create_hint_img('tachibana/age\nencrypted email', max_w=200))
|
||||
msg.add_related(img_bytes, 'image', 'png', cid=hint_img_cid)
|
||||
|
||||
sys.stdout.buffer.write(bytes(msg))
|
||||
if not smtp_server:
|
||||
sys.stdout.buffer.write(bytes(msg))
|
||||
|
||||
else:
|
||||
smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)
|
||||
if smtp_user:
|
||||
if smtp_password is None:
|
||||
smtp_password = click.prompt('Please input SMTP password', hide_input=True)
|
||||
smtp.login(smtp_user, smtp_password)
|
||||
smtp.send_message(msg)
|
||||
smtp.quit()
|
||||
print('Message sent!')
|
||||
|
||||
if __name__ == '__main__':
|
||||
#print(pack_html('foobar'))
|
||||
#with open('/tmp/test.png', 'wb') as f:
|
||||
# f.write(img_to_bytes(create_hint_img('tachibana/age\nencrypted email', max_w=200)))
|
||||
create_age_email()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue