diff --git a/Dockerfile b/Dockerfile index adc00ce..0db61fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,4 +18,4 @@ FROM redis:6.2 as runner ARG REDICRYPT_KEY=default ENV REDICRYPT_KEY ${REDICRYPT_KEY} COPY --from=builder /build/dist/redicrypt.so /usr/local/lib/redicrypt.so -ENTRYPOINT REDICRYPT_KEY=${REDICRYPT_KEY} /usr/local/bin/redis-server --load-module /usr/local/lib/redicrypt.so +ENTRYPOINT REDICRYPT_KEY=${REDICRYPT_KEY} /usr/local/bin/redis-server --loadmodule /usr/local/lib/redicrypt.so diff --git a/Makefile b/Makefile index d94ba7b..1200573 100644 --- a/Makefile +++ b/Makefile @@ -9,11 +9,12 @@ deps/redismodule.h: @mkdir deps @wget -q -O $@ https://raw.githubusercontent.com/redis/redis/unstable/src/redismodule.h -${DISTDIR}/${PROGROOT}_go.a: ${PROGROOT}.go +${DISTDIR}/${PROGROOT}_go.a: c_bridge.go + go mod download go build -buildmode=c-archive -o $@ $? -${DISTDIR}/${PROGROOT}_go.h: ${PROGROOT}.go - go build -buildmode=c-shared -o ${DISTDIR}/${PROGROOT}_go.so $? +${DISTDIR}/${PROGROOT}_go.h: c_bridge.go + go build -buildmode=c-shared -o ${DISTDIR}/${PROGROOT}_go.so $? src/redicrypt ${DISTDIR}/${PROGROOT}.o: ${PROGROOT}.c ${DISTDIR}/${PROGROOT}_go.h deps/redismodule.h gcc -w -fPIC -std=gnu99 -c -static -o $@ $< @@ -24,5 +25,14 @@ ${DISTDIR}/${PROGROOT}.so: ${DISTDIR}/${PROGROOT}_go.a ${DISTDIR}/${PROGROOT}.o clean: rm -rf ${DISTDIR} -docker:: ${DISTDIR}/${PROGROOT}.so - docker build . +docker:: + docker build -t ${PROGROOT}:latest . + +test:: + cd src/redicrypt && go test + +run:: ${DISTDIR}/${PROGROOT}.so + REDICRYPT_KEY=12345678901234567890123456789012 redis-server --loadmodule ${DISTDIR}/${PROGROOT}.so + +test_docker:: docker + docker run --rm --name ${PROGROOT} ${PROGROOT}:latest diff --git a/README.md b/README.md index 3ea24b0..fe4a886 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,45 @@ Redicrypt stores strings, encrypted, in redis. Encryption takes place on the red It does this by introducing two new redis commands, one for storing an encrypted key value, and one for retrieving the decrypted value of the key. Key names are stored in plaintext, and only their values are decrypted. -* SETENC - Sets a key to an encrypted value - - eg: SETENC *somekey* *myvalue* +* RC.SETENC - Sets a key to an encrypted value + - eg: RC.SETENC *somekey* *myvalue* -* GETDEC - Gets the decrypted value of a key - - eg: GETDEC *somekey* +* RC.GETENC - Gets the decrypted value of a key + - eg: RC.GETENC *somekey* -* RECRYPT - Fetches a key, decrypts it, and re-encrypts it with our new key: - - eg: RECRYPT *somekey* +* RC.BSETENC - Base64encode a key, storing the encrypted value + - eg: RC.BSETENC *somekey* *myvalue* + +* RC.BGETENC - Return the decrypted value of a base64encoded key + - eg: RC.BGETENC *somekey* + +* RC.RECRYPT - Fetches a key, decrypts it, and re-encrypts it with our new key: + - eg: RC.RECRYPT *somekey* + +* RC.SETHASH - Sets a key to a hashed value. The first argument is the hash type. + - eg: RC.SETHASH *sha224* *somekey* *myvalue* + +* RC.SETB64 - Set a key to the bsae64 encoded value of the specified string. + - eg: RC.SETB64 *somekey* *myvalue* + +* RC.GETB64 - Get the plaintext value of a base64 encoded redis key. + - eg: RC.GETB64 *somekey* + +* RC.SETHASH - Sets a key to a hashed value. The first argument is the hash type. + - eg: RC.SETHASH *sha224* *somekey* *myvalue* + +### Supported Hashtypes + +The following are the supported hashtypes to use with SETHASH. An unsupported type will return a blank string. + +1. sha1 +1. sha224 +1. sha256 +1. sha3-224 +1. sha3-256 +1. sha3-384 +1. sha3-512 +1. whirlpool ## Usage diff --git a/c_bridge.go b/c_bridge.go new file mode 100644 index 0000000..b8d1bf6 --- /dev/null +++ b/c_bridge.go @@ -0,0 +1,44 @@ +package main + +import "C" + +import ( + "github.com/chayim/redicrypt/src/redicrypt" +) + +//export Hash +func Hash(hashType, value *C.char) *C.char { + hashName := string(C.GoString(hashType)) + hashVal := []byte(C.GoString(value)) + return C.CString(redicrypt.Hash(hashName, hashVal)) +} + +//export Base64Encode +func Base64Encode(value *C.char) *C.char { + cstr := redicrypt.B64Encode([]byte(C.GoString(value))) + return C.CString(cstr) +} + +//export Base64Decode +func Base64Decode(encodedText *C.char) *C.char { + encoded := string(C.GoString(encodedText)) + cstr := redicrypt.B64Decode(encoded) + return C.CString(string(cstr)) +} + +//export Encrypt +func Encrypt(encKey *C.char, value *C.char) *C.char { + secret := []byte(C.GoString(encKey)) + plaintext := []byte(C.GoString(value)) + cstr := redicrypt.Encrypt(secret, plaintext) + return C.CString(cstr) +} + +//export Decrypt +func Decrypt(encKey *C.char, value *C.char) *C.char { + secret := []byte(C.GoString(encKey)) + encryptedText := []byte(C.GoString(value)) + return C.CString(redicrypt.Decrypt(secret, encryptedText)) +} + +func main() {} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f17e066 --- /dev/null +++ b/go.mod @@ -0,0 +1,12 @@ +module github.com/chayim/redicrypt + +go 1.16 + +require ( + github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 // indirect + golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect + golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect + golang.org/x/term v0.0.0-20210317153231-de623e64d2a6 // indirect + golang.org/x/text v0.3.6 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..111bd6a --- /dev/null +++ b/go.sum @@ -0,0 +1,147 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/glaslos/ssdeep v0.3.1 h1:Zc0QgVdtX2LBvVQjFoFhaa8wIqSetUitiJTj9NEWoIY= +github.com/glaslos/ssdeep v0.3.1/go.mod h1:PlZQFbsBZyQURIdDRUcOfLm/yOXzgoPcv+8B3MBg7Rk= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004 h1:G+9t9cEtnC9jFiTxyptEKuNIAbiN5ZCQzX2a74lj3xg= +github.com/jzelinskie/whirlpool v0.0.0-20201016144138-0675e54bb004/go.mod h1:KmHnJWQrgEvbuy0vcvj00gtMqbvNn1L+3YUZLK/B92c= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210317153231-de623e64d2a6 h1:EC6+IGYTjPpRfv9a2b/6Puw0W+hLtAhkV1tPsXhutqs= +golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/redicrypt.c b/redicrypt.c index a3c0083..fba6764 100644 --- a/redicrypt.c +++ b/redicrypt.c @@ -9,6 +9,72 @@ const RedisModuleString* _encrypt(RedisModuleCtx *ctx, char* ptr) { return encrypted; } +const RedisModuleString* _decrypt(RedisModuleCtx *ctx, const char* key, char* ptr) { + const char *res = Decrypt(key, ptr); + RedisModuleString *decrypted = RedisModule_CreateString(ctx, res, strlen(res)); + return decrypted; +} + +/* Set a redis key to a base64-encoded value */ +int SetB64Command (RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + if (argc != 3) return RedisModule_WrongArity(ctx); + RedisModule_AutoMemory(ctx); + size_t s; + const char *str = RedisModule_StringPtrLen(argv[2], &s); + + const char *res = Base64Encode(str); + RedisModuleString *encoded = RedisModule_CreateString(ctx, res, strlen(res)); + RedisModuleCallReply *srep = RedisModule_Call(ctx, "SET", "ss", argv[1], encoded); + + if (RedisModule_CallReplyType(srep) == REDISMODULE_REPLY_ERROR) { + return RedisModule_ReplyWithCallReply(ctx, srep); + } + + RedisModule_ReplyWithSimpleString(ctx, "OK"); + + return REDISMODULE_OK; +} + +/* Unbase-64encode a redis key value */ +int GetB64Command (RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + if (argc != 2) return RedisModule_WrongArity(ctx); + RedisModule_AutoMemory(ctx); + + RedisModuleCallReply *reply = RedisModule_Call(ctx, "GET", "s", argv[1]); + if (RedisModule_CallReplyType(reply) == REDISMODULE_REPLY_ERROR) { + return RedisModule_ReplyWithCallReply(ctx, reply); + } + size_t len; + char *ptr = RedisModule_CallReplyStringPtr(reply, &len); + + const char *res = Base64Decode(ptr); + RedisModuleString *unhashed = RedisModule_CreateString(ctx, res, strlen(res)); + RedisModule_ReplyWithString(ctx, unhashed); + + return REDISMODULE_OK; +} + +/* Set the encrypted value for a key, b64encoding the key */ +int BSetEncCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + if (argc != 3) return RedisModule_WrongArity(ctx); + RedisModule_AutoMemory(ctx); + + size_t s; + const char *str = RedisModule_StringPtrLen(argv[2], &s); + + RedisModuleString *ciphered = _encrypt(ctx, str); + const char *res = Base64Encode(argv[1]); + RedisModuleString *key= RedisModule_CreateString(ctx, res, strlen(res)); + RedisModuleCallReply *srep = RedisModule_Call(ctx, "SET", "ss", key, ciphered); + + if (RedisModule_CallReplyType(srep) == REDISMODULE_REPLY_ERROR) { + return RedisModule_ReplyWithCallReply(ctx, srep); + } + RedisModule_ReplyWithSimpleString(ctx, "OK"); + return REDISMODULE_OK; + +} + /* Set an encrypted value */ int SetEncCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 3) return RedisModule_WrongArity(ctx); @@ -17,7 +83,6 @@ int SetEncCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { size_t s; const char *str = RedisModule_StringPtrLen(argv[2], &s); - //const char *ptr = Encrypt(getenv("REDICRYPT_KEY"), str); RedisModuleString *ciphered = _encrypt(ctx, str); RedisModuleCallReply *srep = RedisModule_Call(ctx, "SET", "ss", argv[1], ciphered); @@ -28,14 +93,31 @@ int SetEncCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { return REDISMODULE_OK; } -const RedisModuleString* _decrypt(RedisModuleCtx *ctx, const char* key, char* ptr) { - const char *res = Decrypt(key, ptr); - RedisModuleString *decrypted = RedisModule_CreateString(ctx, res, strlen(res)); - return decrypted; +/* Set a value, hashed + * [1] = Hash Type + * [2] = Redis key to set + * [3] = Redis value to hash */ +int SetHashCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + if (argc != 4) return RedisModule_WrongArity(ctx); + RedisModule_AutoMemory(ctx); + + size_t s; + const char *hashType = RedisModule_StringPtrLen(argv[1], &s); + const char *str = RedisModule_StringPtrLen(argv[3], &s); + + const char *res = Hash(hashType, str); + RedisModuleString *hashed = RedisModule_CreateString(ctx, res, strlen(res)); + RedisModuleCallReply *srep = RedisModule_Call(ctx, "SET", "ss", argv[2], hashed); + + if (RedisModule_CallReplyType(srep) == REDISMODULE_REPLY_ERROR) { + return RedisModule_ReplyWithCallReply(ctx, srep); + } + RedisModule_ReplyWithSimpleString(ctx, "OK"); + return REDISMODULE_OK; } /* Decrypt an existing redis key, returning the existing string. */ -int GetDecCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { +int GetEncCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 2) return RedisModule_WrongArity(ctx); RedisModule_AutoMemory(ctx); @@ -53,6 +135,28 @@ int GetDecCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { return REDISMODULE_OK; } +/* Decrypt an existing redis key, returning the existing string. */ +int BGetEncCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + + if (argc != 2) return RedisModule_WrongArity(ctx); + RedisModule_AutoMemory(ctx); + + const char *res = Base64Decode(argv[1]); + RedisModuleString *key = RedisModule_CreateString(ctx, res, strlen(res)); + + RedisModuleCallReply *reply = RedisModule_Call(ctx, "GET", "s", key); + if (RedisModule_CallReplyType(reply) == REDISMODULE_REPLY_ERROR) { + return RedisModule_ReplyWithCallReply(ctx, reply); + } + size_t len; + char *ptr = RedisModule_CallReplyStringPtr(reply,&len); + + RedisModuleString *decrypted = _decrypt(ctx, getenv("REDICRYPT_KEY"), ptr); + RedisModule_ReplyWithString(ctx, decrypted); + + return REDISMODULE_OK; +} + /* Decrypt existing encrypted key, and recrypt */ int RecryptCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc >= 2) return RedisModule_WrongArity(ctx); @@ -68,7 +172,6 @@ int RecryptCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // decrypted RedisModuleString *decrypted = _decrypt(ctx, getenv("OLD_REDICRYPT_KEY"), ptr); - size_t *enc_len; const char *dechar = RedisModule_StringPtrLen(decrypted, enc_len); @@ -87,20 +190,44 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) if (RedisModule_Init(ctx,"redicrypt",1,REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; - if (RedisModule_CreateCommand(ctx,"SETENC", + if (RedisModule_CreateCommand(ctx,"RC.SETENC", SetEncCommand, "write", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; - if (RedisModule_CreateCommand(ctx,"DECGET", - GetDecCommand, "readonly", + if (RedisModule_CreateCommand(ctx,"RC.BSETENC", + BSetEncCommand, "write", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; - if (RedisModule_CreateCommand(ctx,"RECRYPT", - RecryptCommand, "write", + if (RedisModule_CreateCommand(ctx,"RC.SETB64", + SetB64Command, "write", + 0, 0, 0) == REDISMODULE_ERR) + return REDISMODULE_ERR; + + if (RedisModule_CreateCommand(ctx,"RC.SETHASH", + SetHashCommand, "write", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; + if (RedisModule_CreateCommand(ctx,"RC.GETB64", + GetB64Command, "readonly", + 0, 0, 0) == REDISMODULE_ERR) + return REDISMODULE_ERR; + + if (RedisModule_CreateCommand(ctx,"RC.BGETENC", + BGetEncCommand, "readonly", + 0, 0, 0) == REDISMODULE_ERR) + return REDISMODULE_ERR; + + if (RedisModule_CreateCommand(ctx,"RC.GETENC", + GetEncCommand, "readonly", + 0, 0, 0) == REDISMODULE_ERR) + return REDISMODULE_ERR; + + if (RedisModule_CreateCommand(ctx,"RC.RECRYPT", + RecryptCommand, "write", + 0, 0, 0) == REDISMODULE_ERR) + return REDISMODULE_ERR; return REDISMODULE_OK; } diff --git a/redicrypt.go b/redicrypt.go deleted file mode 100644 index d2d102d..0000000 --- a/redicrypt.go +++ /dev/null @@ -1,67 +0,0 @@ -package main - -import "C" - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/rand" - "encoding/base64" - "io" -) - -//export Encrypt -func Encrypt(encKey *C.char, value *C.char) *C.char { - secret := []byte(C.GoString(encKey)) - plaintext := []byte(C.GoString(value)) - - block, err := aes.NewCipher(secret) - if err != nil { - panic(err) - } - - ciphertext := make([]byte, aes.BlockSize+len(plaintext)) - iv := ciphertext[:aes.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - panic(err) - } - - stream := cipher.NewCFBEncrypter(block, iv) - stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) - cstr := base64.URLEncoding.EncodeToString(ciphertext) - return C.CString(cstr) -} - -//export Decrypt -func Decrypt(encKey *C.char, value *C.char) *C.char { - - secret := []byte(C.GoString(encKey)) - encryptedText := C.GoString(value) - - block, err := aes.NewCipher(secret) - if err != nil { - panic(err) - } - - if len(encryptedText) < aes.BlockSize { - panic("ciphertext too short") - } - - cstr, err := base64.URLEncoding.DecodeString(encryptedText) - if err != nil { - panic(err) - } - - iv := cstr[:aes.BlockSize] - cstr = cstr[aes.BlockSize:] - - stream := cipher.NewCFBDecrypter(block, iv) - - // XORKeyStream can work in-place if the two arguments are the same. - stream.XORKeyStream(cstr, cstr) - - return C.CString(string(cstr)) - -} - -func main() {} diff --git a/src/redicrypt/cryptlib.go b/src/redicrypt/cryptlib.go new file mode 100644 index 0000000..f07a8c4 --- /dev/null +++ b/src/redicrypt/cryptlib.go @@ -0,0 +1,113 @@ +package redicrypt + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha1" + "crypto/sha256" + "encoding/base64" + "github.com/jzelinskie/whirlpool" + "golang.org/x/crypto/sha3" + "io" +) + +// Wrapper for hashing functions, returns base64encoded hashes +func Hash(hashName string, hashVal []byte) string { + switch { + + case hashName == "sha1": + hv := sha1.Sum(hashVal) + return B64Encode(hv[:]) + + case hashName == "sha224": + hv := sha256.Sum224(hashVal) + return B64Encode(hv[:]) + + case hashName == "sha256": + hv := sha256.Sum256(hashVal) + return B64Encode(hv[:]) + + case hashName == "sha3-224": + hv := sha3.Sum224(hashVal) + return B64Encode(hv[:]) + + case hashName == "sha3-256": + hv := sha3.Sum256(hashVal) + return B64Encode(hv[:]) + + case hashName == "sha3-384": + hv := sha3.Sum384(hashVal) + return B64Encode(hv[:]) + + case hashName == "sha3-512": + hv := sha3.Sum512(hashVal) + return B64Encode(hv[:]) + + case hashName == "whirlpool": + h := whirlpool.New() + io.WriteString(h, string(hashVal)) + return B64Encode(h.Sum(nil)) + } + return "" + +} + +// Wrapper for encoding, specifically so that we can unit test to go code. +func B64Encode(encoded []byte) string { + cstr := base64.URLEncoding.EncodeToString(encoded) + + return cstr +} + +// Wrapper for decoding, specifically so that we can unit test to go code. +func B64Decode(encoded string) []byte { + cstr, err := base64.URLEncoding.DecodeString(encoded) + if err != nil { + return nil + } + + return cstr +} + +func Encrypt(secret, plaintext []byte) string { + + block, err := aes.NewCipher(secret) + if err != nil { + return "" + } + + ciphertext := make([]byte, aes.BlockSize+len(plaintext)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + return "" + } + + stream := cipher.NewCFBEncrypter(block, iv) + stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) + + return B64Encode(ciphertext) +} + +func Decrypt(secret, cipherText []byte) string { + block, err := aes.NewCipher(secret) + if err != nil { + return "" + } + + if len(cipherText) < aes.BlockSize { + return "" + } + + cstr := B64Decode(string(cipherText)) + + iv := cstr[:aes.BlockSize] + cstr = cstr[aes.BlockSize:] + + stream := cipher.NewCFBDecrypter(block, iv) + + // XORKeyStream can work in-place if the two arguments are the same. + stream.XORKeyStream(cstr, cstr) + return string(cstr) + +} diff --git a/src/redicrypt/cryptlib_test.go b/src/redicrypt/cryptlib_test.go new file mode 100644 index 0000000..222b52d --- /dev/null +++ b/src/redicrypt/cryptlib_test.go @@ -0,0 +1,112 @@ +package redicrypt + +import ( + "testing" +) + +func TestBase64Encoding(t *testing.T) { + charthing := []byte("these are the days of our lives") + res := B64Encode(charthing) + benc := "dGhlc2UgYXJlIHRoZSBkYXlzIG9mIG91ciBsaXZlcw==" + if res != benc { + t.Errorf("received %s instead of %s", res, benc) + } +} + +func TestBase64Decoding(t *testing.T) { + phrase := "these are the days of our lives" + benc := "dGhlc2UgYXJlIHRoZSBkYXlzIG9mIG91ciBsaXZlcw==" + res := string(B64Decode(benc)) + if res != phrase { + t.Errorf("received %s instead of %s", res, phrase) + } +} + +func TestHashing(t *testing.T) { + phrase := []byte("these are the days of our lives") + + // sha1 + expected := "_2-CY4CRhEmH1o9mOCCpNgbONX4=" + sha1 := Hash("sha1", phrase) + if expected != sha1 { + t.Errorf("received %s instead of %s", sha1, expected) + } + + // sha224 + sha224 := Hash("sha224", phrase) + expected = "JOUSOU6XViAkX-nMUgte0FU7huRqXag3ls431A==" + if expected != sha224 { + t.Errorf("received %s instead of %s", sha224, expected) + } + + sha256 := Hash("sha256", phrase) + expected = "Se_qTlwCwsvDSKRoR3VB7faouqfG2Bnd1Afq1g5csZI=" + if expected != sha256 { + t.Errorf("received %s instead of %s", sha256, expected) + } + + // sha3-224 + sha3224 := Hash("sha3-224", phrase) + expected = "7WXdRxLyl1cNlWQ-IIFVPNtgY4h-XqmRKPZ8CA==" + if expected != sha3224 { + t.Errorf("received %s instead of %s", sha3224, expected) + } + + // sha3-256 + sha3256 := Hash("sha3-256", phrase) + expected = "qNdzthgF18r3a30BIUsCwQXhwELbbu6rqb3AXrekyHQ=" + if expected != sha3256 { + t.Errorf("received %s instead of %s", sha3256, expected) + } + + // sha3-384 + sha3384 := Hash("sha3-384", phrase) + expected = "FdN3K5SiDFXhhLDjJxK9snJVw36eLziRybS7c3wN3OypypbevWrNNSYorEW5GSdm" + if expected != sha3384 { + t.Errorf("received %s instead of %s", sha3384, expected) + } + + // sha3-512 + sha3512 := Hash("sha3-512", phrase) + expected = "NlOyTm-9c9fwC5PTnEIXJNjZ7We95aW9CiBsrJqnfdp9Eg2-_uUT2gRYRTM1vAXg2XBpz0Pm29uyW6ig1gK2_A==" + if expected != sha3512 { + t.Errorf("received %s instead of %s", sha3512, expected) + } + + // whirlpool + wp := Hash("whirlpool", phrase) + expected = "deuZC3eAkN0lsktV94r_FP0VBdb6ZW_Y5q2qr6g0KGGMuUdDW3zYAOlSWtoW4-DEfbZSkLxHg-iJZl0dV_vZpw==" + if expected != wp { + t.Errorf("received %s instead of %s", wp, expected) + } + + // BOGUS + ssd := Hash("IAMABOGUS", phrase) + expected = "" + if expected != ssd { + t.Errorf("received %s instead of %s", ssd, expected) + } + +} + +func TestEncrypt(t *testing.T) { + plaintext := []byte("these are the days of our lives") + secret := []byte("12345678901234567890123456789012") + + enc := Encrypt(secret, plaintext) + if enc == string(secret) { + t.Errorf("received decrypted text") + } +} + +func TestDecrypt(t *testing.T) { + plaintext := []byte("these are the days of our lives") + secret := []byte("12345678901234567890123456789012") + ciphered := []byte(Encrypt(secret, plaintext)) + + dec := Decrypt(secret, ciphered) + if dec != string(plaintext) { + t.Errorf("failed decrypting") + } + +}