mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-14 17:09:57 -05:00
* adds pkg/jmap/jmap_integration_test.go
* uses ghcr.io/stalwartlabs/stalwart:v0.13.2-alpine
* can be disabled by setting one of the following environment
variables, in the same fashion as ca0493b28
- CI=woodpecker
- CI_SYSTEM_NAME=woodpecker
- USE_TESTCONTAINERS=false
* dependencies:
- bump github.com/go-test/deep from 1.1.0 to 1.1.1
- add github.com/cention-sany/utf7
- add github.com/dustinkirkland/golang-petname
- add github.com/emersion/go-imap/v2
- add github.com/emersion/go-message
- add github.com/emersion/go-sasl
- add github.com/go-crypt/crypt
- add github.com/go-crypt/x
- add github.com/gogs/chardet
- add github.com/inbucket/html2text
- add github.com/jhilleryerd/enmime/v2
- add github.com/ssor/bom
- add gopkg.in/loremipsum.v1
301 lines
5.2 KiB
Go
301 lines
5.2 KiB
Go
package crypt
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/md5"
|
|
"crypto/sha1"
|
|
"crypto/sha256"
|
|
"crypto/sha512"
|
|
"hash"
|
|
"strconv"
|
|
)
|
|
|
|
// KeySHACrypt calculates the shacrypt SHA256/SHA512 key given an appropriate hash.Hash, password, salt, and number of rounds.
|
|
func KeySHACrypt(hashFunc func() hash.Hash, password, salt []byte, rounds int) []byte {
|
|
// Step 1.
|
|
digest := hashFunc()
|
|
|
|
size := digest.Size()
|
|
|
|
switch size {
|
|
case sha1.Size:
|
|
return KeySHA1Crypt(password, salt, uint32(rounds))
|
|
case sha256.Size, sha512.Size:
|
|
break
|
|
default:
|
|
return nil
|
|
}
|
|
|
|
length := len(password)
|
|
|
|
// Step 2.
|
|
digest.Write(password)
|
|
|
|
// Step 3.
|
|
digest.Write(salt)
|
|
|
|
// Step 4.
|
|
digestB := hashFunc()
|
|
|
|
// Step 5.
|
|
digestB.Write(password)
|
|
|
|
// Step 6.
|
|
digestB.Write(salt)
|
|
|
|
// Step 7.
|
|
digestB.Write(password)
|
|
|
|
// Step 8.
|
|
sumB := digestB.Sum(nil)
|
|
digestB.Reset()
|
|
digestB = nil
|
|
|
|
// Step 9 and 10:
|
|
digest.Write(repeat(sumB, length))
|
|
|
|
// Step 11.
|
|
for i := length; i > 0; i >>= 1 {
|
|
if even(i) {
|
|
digest.Write(password)
|
|
} else {
|
|
digest.Write(sumB)
|
|
}
|
|
}
|
|
|
|
clean(sumB)
|
|
sumB = nil
|
|
|
|
// Step 12.
|
|
sumA := digest.Sum(nil)
|
|
digest.Reset()
|
|
|
|
// Step 13-14.
|
|
for i := 0; i < length; i++ {
|
|
digest.Write(password)
|
|
}
|
|
|
|
// Step 15.
|
|
sumDP := digest.Sum(nil)
|
|
digest.Reset()
|
|
|
|
// Step 16.
|
|
seqP := repeat(sumDP, length)
|
|
sumDP = nil
|
|
|
|
// Step 17-18.
|
|
for i := 0; i < 16+int(sumA[0]); i++ {
|
|
digest.Write(salt)
|
|
}
|
|
|
|
// Step 19.
|
|
sumDS := digest.Sum(nil)
|
|
digest.Reset()
|
|
|
|
// Step 20.
|
|
seqS := repeat(sumDS, len(salt))
|
|
|
|
// Step 21.
|
|
for i := 0; i < rounds; i++ {
|
|
digest.Reset()
|
|
|
|
// Step 21 Sub-Step B and C.
|
|
if i&1 != 0 {
|
|
// Step 21 Sub-Step B.
|
|
digest.Write(seqP)
|
|
} else {
|
|
// Step 21 Sub-Step C.
|
|
digest.Write(sumA)
|
|
}
|
|
|
|
// Step 21 Sub-Step D.
|
|
if i%3 != 0 {
|
|
digest.Write(seqS)
|
|
}
|
|
|
|
// Step 21 Sub-Step E.
|
|
if i%7 != 0 {
|
|
digest.Write(seqP)
|
|
}
|
|
|
|
// Step 21 Sub-Step F and G.
|
|
if i&1 != 0 {
|
|
// Step 21 Sub-Step F.
|
|
digest.Write(sumA)
|
|
} else {
|
|
// Step 21 Sub-Step G.
|
|
digest.Write(seqP)
|
|
}
|
|
|
|
// Sub-Step H.
|
|
copy(sumA, digest.Sum(nil))
|
|
}
|
|
|
|
digest.Reset()
|
|
digest = nil
|
|
|
|
seqP, seqS = nil, nil
|
|
|
|
switch size {
|
|
case sha256.Size:
|
|
// Step 22 Sub Step E.
|
|
return permute(sumA, permuteTableSHACryptSHA256[:])
|
|
case sha512.Size:
|
|
// Step 22 Sub Step E.
|
|
return permute(sumA, permuteTableSHACryptSHA512[:])
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// KeySHA1Crypt calculates the sha1crypt key given a password, salt, and number of rounds.
|
|
func KeySHA1Crypt(password, salt []byte, rounds uint32) []byte {
|
|
digest := hmac.New(sha1.New, password)
|
|
digest.Write(salt)
|
|
digest.Write(prefixSHA1Crypt)
|
|
digest.Write([]byte(strconv.FormatUint(uint64(rounds), 10)))
|
|
|
|
sumA := digest.Sum(nil)
|
|
|
|
if rounds == 0 {
|
|
return permute(sumA, permuteTableSHA1Crypt[:])
|
|
}
|
|
|
|
for rounds--; rounds > 0; rounds-- {
|
|
digest.Reset()
|
|
|
|
digest.Write(sumA)
|
|
|
|
copy(sumA, digest.Sum(nil))
|
|
}
|
|
|
|
return permute(sumA, permuteTableSHA1Crypt[:])
|
|
}
|
|
|
|
// KeyMD5Crypt calculates the md5crypt key given a password and salt.
|
|
func KeyMD5Crypt(password, salt []byte) []byte {
|
|
length := len(password)
|
|
|
|
digest := md5.New()
|
|
|
|
digest.Write(password)
|
|
digest.Write(salt)
|
|
digest.Write(password)
|
|
|
|
sumB := digest.Sum(nil)
|
|
|
|
digest.Reset()
|
|
|
|
digest.Write(password)
|
|
digest.Write(prefixMD5Crypt)
|
|
digest.Write(salt)
|
|
digest.Write(repeat(sumB, length))
|
|
|
|
clean(sumB)
|
|
|
|
for i := length; i > 0; i >>= 1 {
|
|
if even(i) {
|
|
digest.Write(password[0:1])
|
|
} else {
|
|
digest.Write([]byte{0})
|
|
}
|
|
}
|
|
|
|
sumA := digest.Sum(nil)
|
|
|
|
for i := 0; i < 1000; i++ {
|
|
digest.Reset()
|
|
|
|
if even(i) {
|
|
digest.Write(sumA)
|
|
} else {
|
|
digest.Write(password)
|
|
}
|
|
|
|
if i%3 != 0 {
|
|
digest.Write(salt)
|
|
}
|
|
|
|
if i%7 != 0 {
|
|
digest.Write(password)
|
|
}
|
|
|
|
if i&1 == 0 {
|
|
digest.Write(password)
|
|
} else {
|
|
digest.Write(sumA)
|
|
}
|
|
|
|
copy(sumA, digest.Sum(nil))
|
|
}
|
|
|
|
return permute(sumA, permuteTableMD5Crypt[:])
|
|
}
|
|
|
|
// KeyMD5CryptSun calculates the md5crypt (Sun Version) key given a password, salt, and number rounds.
|
|
func KeyMD5CryptSun(password, salt []byte, rounds uint32) []byte {
|
|
digest := md5.New()
|
|
|
|
digest.Write(password)
|
|
|
|
if rounds == 0 {
|
|
digest.Write(prefixSunMD5Crypt)
|
|
digest.Write(salt)
|
|
digest.Write(sepCrypt)
|
|
} else {
|
|
digest.Write(prefixSunMD5CryptRounds)
|
|
digest.Write([]byte(strconv.FormatUint(uint64(rounds), 10)))
|
|
digest.Write(sepCrypt)
|
|
digest.Write(salt)
|
|
digest.Write(sepCrypt)
|
|
}
|
|
|
|
sumA := digest.Sum(nil)
|
|
|
|
iterations := uint32(rounds + 4096)
|
|
|
|
bit := func(off uint32) uint32 {
|
|
off %= 128
|
|
if (sumA[off/8] & (0x01 << (off % 8))) != 0 {
|
|
return 1
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
var ind7 [md5.Size]byte
|
|
|
|
for i := uint32(0); i < iterations; i++ {
|
|
digest.Reset()
|
|
|
|
digest.Write(sumA)
|
|
|
|
for j := 0; j < md5.Size; j++ {
|
|
off := (j + 3) % 16
|
|
ind4 := (sumA[j] >> (sumA[off] % 5)) & 0x0F
|
|
sh7 := (sumA[off] >> (sumA[j] % 8)) & 0x01
|
|
ind7[j] = (sumA[ind4] >> sh7) & 0x7F
|
|
}
|
|
|
|
var indA, indB uint32
|
|
|
|
for j := uint(0); j < 8; j++ {
|
|
indA |= bit(uint32(ind7[j])) << j
|
|
indB |= bit(uint32(ind7[j+8])) << j
|
|
}
|
|
|
|
indA = (indA >> bit(i)) & 0x7F
|
|
indB = (indB >> bit(i+64)) & 0x7F
|
|
|
|
if bit(indA)^bit(indB) == 1 {
|
|
digest.Write(magicTableMD5CryptSunHamlet[:])
|
|
}
|
|
|
|
digest.Write([]byte(strconv.FormatUint(uint64(i), 10)))
|
|
|
|
copy(sumA, digest.Sum(nil))
|
|
}
|
|
|
|
return permute(sumA, permuteTableMD5Crypt[:])
|
|
}
|