the code challenge exercises dealing with Secure Digital Message Signing using RSA
provide an application that meets the following requirements:
- given a string input of up to 250 characters, return a JSON response compliant to the included schema
- generate a public/private RSA or ECDSA keypair and persisting the keypair on the filesystem
- subsequent invocations of your application should read from the same files
- document the code
- use first order libraries, you may not use any third party libraries or packages.
- golang (version 1.10 is required)
- docker container manager installed on osx, linux, or windows 10
<create new root dir somewhere>
$ mkdir jfrailey; cd jfrailey
// "go get" will build a new binary executable in your $GOBIN and defaults to jfrailey/bin if not set
$ go get github.com/dfense/codechal/smartedge
// build a deployable docker container
$ cd src/github.com/dfense/codechal
$ docker build . -t codechal
// and now the fun part...
// when the container first runs, there will be no rsa private/public keys available,
// and container will creates them
// to meet the requirement reusing the same rsa private/public keys between runs, export a volume
// to local drive so the keys don't go away. also, to avoid building up a lot of docker images, i use --rm
// to remove them after they run each time. The original docker image stays in tact
// be sure to create a local host directory to mount, if you want to persist the keys
$ mkdir certs
$ docker run --rm -v $PWD/certs:/dfense/certs codechal
sample output of the run above meeting the requirements of the json schema format. Validation is built into the unit tests and verified with external tools as well such as openssl (more complex) and even simple online one here: https://8gwifi.org/RSAFunctionality?rsasignverifyfunctions=rsasignverifyfunctions&keysize=2048
Be sure to set Sha256 radio button, and upload the certs generated by the container on your mounted volume
{
"message": "john@hupla.com",
"signature": "v1rTgB3deCim/amZxGk0PmI7uqz7kdj3Ztsp2lWMjYAEB1rLPU1EojCnWdCQvEffUA6YYQmxarF23ZYkQJW527hLY6AYWj8AgsMZo25ak3fG6kAplQJBlcGQEWWTdE9bXV4DMGRy4zXSF/zc2L1wrzUR1Im7EEx0r5QJ2EfJx0xuQENrbvnyztJeYTNj+/ZnGphcRooblltw5KIUW4V3Fr4cmjdJ2gepwxhxdJN7qBDEXZXn46zNy2jM91jyD/BhvDd+lI6j/YUDqBYYqi5lMlUH6RPouuPvepYLA4EvXtk4m+9ZFUJW17ffLHeEEvVekLMcfYocXxxv6EtD1kATfA==",
"pubkey": "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1qPrDg88ZsTRDkt1NXvi\nm1xWXU8h7OFFSDXxGqSm1twaONaS+uaNCBt9EqVs7MIAvyFQLnVvrd3elNcyncjI\nH4LfjI4WoEtuWxYoddsXjcsnPnIOeVMVI7Nx/LQEl9Mpj7iYPWhpkT1FGLpbz3Rk\n4JGHMptDQTkQNxT/+Nk5N1LFMnvtZEyQJlmIeiK5TDFVx6bU0cTtqz1fc3RS3OMA\nkYuWdgjJdWxBp6FPbyhHLK9z+alNQsIT9NrWR67qaIPasb4YT3puY836SQipYa1x\nTLloF8p7GKBb2JEyK6OKJtiGemHx5W7qRSFiRoA/JrDtwPk55BXj08hQ7bOZBEbl\n8wIDAQAB\n-----END RSA PUBLIC KEY-----\n"
}
Of course it can be ran inside or outside the container. Simplest use for options, is to run the command with -h parameter to look at mandatory args and optional params
to get an interactive shell with the container, just use following command and then run the program as shown
# docker run -it --entrypoint /bin/bash codechal
# bin/smartedge -h
// produces output
Usage of bin/smartedge:
-gen_new_keys
generate new rsa keys
-rsa_keysize int
set rsa key size. ignore if keys already created (default 2048)
// now sign a message
# bin/smartedge john@hupla.com
// should produce output same as message above
*run program to receive usage format*
run it from your own shell to execute inside the container with dynamic args to executable. this removes the container run layer after complete. the original container image left in tact
$ docker run -it --rm --entrypoint /dfense/bin/smartedge codechal john@hupla.com
to keep the exercise time manageable, some compromises as always where made. This can be easily reconciled with more effort applied. a short list of the obvious ones follow
- run the code as a RESTFUL HTTP API. All the main driver would be easily stubbed out with a REST http service call
- make highly concurrent. few areas such as keygen would need mutex locking
- add more options for keygen including ECDSA as immediate next, and more params for each.
- Interfaces (such as crypto.Signer) to abstract multiple implementations underneath.
- add POST json body for submitting all the new control
- provide a POST call in and add more controllable params to work with new features
- add gRPC service, protobuff packet exchanges for machine to machine usage, and central key sharing
- centralized error strings on any possible failure points to better manage the error strings and comparors if code grows