Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on: [push, pull_request]
jobs:
build:
strategy:
fail-fast: true
fail-fast: false
max-parallel: 20
matrix:
branch: [master]
Expand Down Expand Up @@ -44,6 +44,25 @@ jobs:
path: nimcrypto
submodules: false

- name: Install build dependencies (Linux i386)
if: runner.os == 'Linux' && matrix.target.cpu == 'i386'
run: |
sudo dpkg --add-architecture i386
sudo apt-get update -qq
sudo DEBIAN_FRONTEND='noninteractive' apt-get install \
--no-install-recommends -yq gcc-multilib g++-multilib libssl-dev:i386
mkdir -p external/bin
cat << EOF > external/bin/gcc
#!/bin/bash
exec $(which gcc) -m32 -mno-adx "\$@"
EOF
cat << EOF > external/bin/g++
#!/bin/bash
exec $(which g++) -m32 -mno-adx "\$@"
EOF
chmod 755 external/bin/gcc external/bin/g++
echo '${{ github.workspace }}/external/bin' >> $GITHUB_PATH

- name: Restore MinGW-W64 (Windows) from cache
if: runner.os == 'Windows'
id: windows-mingw-cache
Expand Down Expand Up @@ -108,6 +127,8 @@ jobs:

- name: Build Nim and associated tools
shell: bash
env:
CC: gcc
run: |
pwd
ls -la
Expand Down
9 changes: 8 additions & 1 deletion nimcrypto.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@ task test, "Runs the test suite":
nimc & " c -f -d:danger -r tests/",
nimc & " c -f -d:danger --threads:on -r tests/",
nimc & " c -f --passC=\"-fsanitize=undefined -fsanitize-undefined-trap-on-error\" --passL:\"-fsanitize=undefined -fsanitize-undefined-trap-on-error\" -r tests/",
nimc & " c -f --mm:orc --threads:on -r tests/"
]

# Nim version 1.6 compiler crashes with `out of memory` on i386.
when defined(cpu64):
testCommands.add nimc & " c -f --mm:orc --threads:on -r tests/"
else:
when (NimMajor, NimMinor) >= (2, 0):
testCommands.add nimc & " c -f --mm:orc --threads:on -r tests/"

when (NimMajor, NimMinor) >= (2, 0):
testCommands.add nimc & " c -f --mm:refc --threads:off --passC=\"-fsanitize=undefined -fsanitize-undefined-trap-on-error\" --passL:\"-fsanitize=undefined -fsanitize-undefined-trap-on-error\" -r tests/"
testCommands.add nimc & " c -f --mm:refc --threads:on --passC=\"-fsanitize=undefined -fsanitize-undefined-trap-on-error\" --passL:\"-fsanitize=undefined -fsanitize-undefined-trap-on-error\" -r tests/"
Expand Down
96 changes: 65 additions & 31 deletions nimcrypto/bcmode.nim
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ type
y: array[16, byte]
basectr: array[16, byte]
buf: array[16, byte]
hbuf: array[16, byte]
aadlen: uint64
datalen: uint64
coffset: uint8

## ECB (Electronic Code Book) Mode

Expand Down Expand Up @@ -967,6 +969,9 @@ func decrypt*[T](
# of decent BearSSL project <https://bearssl.org>.
# Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>

const
GCMBlockSize = 128 div 8

func bmul64(x, y: uint64): uint64 =
var x0, x1, x2, x3, y0, y1, y2, y3, z0, z1, z2, z3: uint64
x0 = x and 0x1111111111111111'u64
Expand Down Expand Up @@ -1103,19 +1108,19 @@ func init*[T](
## You can see examples of usage GCM mode here ``examples/gcm.nim``.
mixin init
# GCM supports only 128bit block ciphers
assert(ctx.sizeBlock() == (128 div 8))
assert(len(key) >= ctx.sizeKey())
doAssert(ctx.sizeBlock() == GCMBlockSize)
doAssert(len(key) >= ctx.sizeKey())
burnMem(ctx)
ctx.cipher.init(key)
ctx.cipher.encrypt(ctx.h, ctx.h)
if len(iv) == 12:
ctx.y[0 ..< 12] = iv.toOpenArray(0, 11)
inc128(ctx.y)
else:
var tmp: array[16, byte]
var tmp: array[GCMBlockSize, byte]
ghash(ctx.y, ctx.h, iv)
beStore32(tmp, 12, uint32(len(iv) shl 3))
ghash(ctx.y, ctx.h, tmp.toOpenArray(0, 15))
ghash(ctx.y, ctx.h, tmp.toOpenArray(0, GCMBlockSize - 1))
ctx.cipher.encrypt(ctx.y, ctx.basectr)
ctx.aadlen = uint64(len(aad))
ctx.datalen = 0
Expand All @@ -1133,21 +1138,33 @@ func encrypt*[T](
## Note that length of ``input`` must be less or equal to length of
## ``output``. Length of ``input`` must not be zero.
mixin encrypt
var ectr: array[16, byte]
assert(len(input) <= len(output))
doAssert(len(input) <= len(output))

var
ectr: array[GCMBlockSize, byte]
length = len(input)
offset = 0

var length = len(input)
var offset = 0
ctx.datalen += uint64(length)
while length > 0:
let uselen = if length < 16: length else: 16
inc128(ctx.y)
let uselen =
if int(ctx.coffset) + length < GCMBlockSize:
length
else:
GCMBlockSize - int(ctx.coffset)
if ctx.coffset == 0:
inc128(ctx.y)
ctx.cipher.encrypt(ctx.y, ectr)
for i in 0..<uselen:
output[offset + i] = ectr[i] xor input[offset + i]
ghash(ctx.buf, ctx.h, output.toOpenArray(offset, offset + uselen - 1))
for i in 0 ..< uselen:
let ch = ectr[int(ctx.coffset) + i] xor input[offset + i]
output[offset + i] = ch
ctx.hbuf[int(ctx.coffset) + i] = ch
length -= uselen
offset += uselen
ctx.coffset = (ctx.coffset + uint8(uselen)) and uint8(GCMBlockSize - 1)
if ctx.coffset == 0:
ghash(ctx.buf, ctx.h, ctx.hbuf.toOpenArray(0, GCMBlockSize - 1))

ctx.datalen += uint64(len(input))

func decrypt*[T](
ctx: var GCM[T],
Expand All @@ -1160,21 +1177,33 @@ func decrypt*[T](
## Note that length of ``input`` must be less or equal to length of
## ``output``. Length of ``input`` must not be zero.
mixin encrypt
var ectr: array[16, byte]
assert(len(input) <= len(output))
doAssert(len(input) <= len(output))

var
ectr: array[GCMBlockSize, byte]
length = len(input)
offset = 0

var length = len(input)
var offset = 0
ctx.datalen += uint64(length)
while length > 0:
let uselen = if length < 16: length else: 16
inc128(ctx.y)
let uselen =
if int(ctx.coffset) + length < GCMBlockSize:
length
else:
GCMBlockSize - int(ctx.coffset)
if ctx.coffset == 0:
inc128(ctx.y)
ctx.cipher.encrypt(ctx.y, ectr)
for i in 0..<uselen:
output[offset + i] = ectr[i] xor input[offset + i]
ghash(ctx.buf, ctx.h, input.toOpenArray(offset, offset + uselen - 1))
for i in 0 ..< uselen:
let ch = ectr[int(ctx.coffset) + i] xor input[offset + i]
output[offset + i] = ch
ctx.hbuf[int(ctx.coffset) + i] = input[offset + i]
length -= uselen
offset += uselen
ctx.coffset = (ctx.coffset + uint8(uselen)) and uint8(GCMBlockSize - 1)
if ctx.coffset == 0:
ghash(ctx.buf, ctx.h, ctx.hbuf.toOpenArray(0, GCMBlockSize - 1))

ctx.datalen += uint64(len(input))

func getTag*[T](
ctx: var GCM[T],
Expand All @@ -1184,18 +1213,23 @@ func getTag*[T](
## ``tag``.
##
## Note that maximum size of ``tag`` is 128 bits (16 bytes).
let taglen = len(tag)
let uselen = if taglen < 16: taglen else: 16
var workbuf: array[16, byte]
var workbuf: array[GCMBlockSize, byte]
let
taglen = len(tag)
uselen = if taglen < GCMBlockSize: taglen else: GCMBlockSize

if ctx.coffset != 0:
ghash(ctx.buf, ctx.h, ctx.hbuf.toOpenArray(0, int(ctx.coffset) - 1))

if taglen > 0:
copyMem(tag, 0, ctx.basectr, 0, uselen)
beStore64(workbuf, 0, ctx.aadlen shl 3)
beStore64(workbuf, 8, ctx.datalen shl 3)
ghash(ctx.buf, ctx.h, workbuf)
for i in 0..<uselen:
for i in 0 ..< uselen:
tag[i] = tag[i] xor ctx.buf[i]

func getTag*[T](ctx: var GCM[T]): array[16, byte] {.noinit.} =
func getTag*[T](ctx: var GCM[T]): array[GCMBlockSize, byte] {.noinit.} =
## Obtain authentication tag from ``GCM[T]`` context ``ctx`` and return it as
## result array.
getTag(ctx, result)
Expand Down Expand Up @@ -1229,8 +1263,8 @@ func decrypt*[T](
##
## Note that length of ``input`` must be less or equal to length of
## ``output``. Length of ``input`` must not be zero.
var dataTag: array[16, byte]
let uselen = min(len(tag), 16)
var dataTag: array[GCMBlockSize, byte]
let uselen = min(len(tag), GCMBlockSize)
ctx.decrypt(input, output)
ctx.getTag(dataTag.toOpenArray(0, uselen - 1))
equalMemFull(
Expand Down
22 changes: 8 additions & 14 deletions tests/bootstrap.bat
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,16 @@ EXIT /B 0
ECHO Building Nim [%NIM_BRANCH%] (%NIM_ARCH%) in %NIM_DIR%
git clone https://github.com/nim-lang/Nim.git "%CD%\%NIM_DIR%"
CD "%CD%\%NIM_DIR%"
IF "%NIM_BRANCH%" == "version-1-6" (
git checkout "%NIM_BRANCH%"
git clone --depth 1 https://github.com/nim-lang/csources_v1
CD csources_v1
git checkout "%NIM_BRANCH%"
SET ARCH=%NIM_ARCH%
IF "%NIM_ARCH%" == "amd64" (
SET ARCH=64
SET PROCESSOR_ARCHITECTURE="amd64"
) ELSE (
git checkout devel
git clone --depth 1 https://github.com/nim-lang/csources_v2
CD csources_v2
SET ARCH=32
SET PROCESSOR_ARCHITECTURE="x86"
)

IF "%NIM_ARCH%" == "amd64" (CALL build64.bat) ELSE (CALL build32.bat)
CD ..
ECHO CSOURCES NIM DONE
bin\nim c --skipParentCfg --noNimblePath --skipUserCfg -d:release koch
koch boot -d:release --skipParentCfg
koch nimble --skipParentCfg
CALL build_all.bat
CD ..
EXIT /B 0

Expand Down
18 changes: 7 additions & 11 deletions tests/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,15 @@ function build_nim {
echo "Building Nim [${NIM_BRANCH}] in ${NIM_DIR}"
git clone https://github.com/nim-lang/Nim.git ${NIM_DIR}
cd "${NIM_DIR}"
if [ "${NIM_BRANCH}" = "version-1-6" ]; then
git checkout "${NIM_BRANCH}"
git clone --depth 1 https://github.com/nim-lang/csources_v1
cd csources_v1 && sh build.sh
git checkout "${NIM_BRANCH}"
if [ "${NIM_ARCH}" = "i386" ]; then
NIM_CPU="i386"
elif [ "${NIM_ARCH}" = "arm64" ]; then
NIM_CPU="arm64"
else
git checkout devel
git clone --depth 1 https://github.com/nim-lang/csources_v2
cd csources_v2 && sh build.sh
NIM_CPU="amd64"
fi
cd ..
bin/nim c --skipParentCfg --noNimblePath --skipUserCfg -d:release koch
./koch boot -d:release
./koch nimble -d:release
./build_all.sh ucpu=${NIM_CPU}
cd ..
}

Expand Down
Loading