summaryrefslogtreecommitdiff
path: root/crypt.go
diff options
context:
space:
mode:
Diffstat (limited to 'crypt.go')
-rw-r--r--crypt.go64
1 files changed, 55 insertions, 9 deletions
diff --git a/crypt.go b/crypt.go
index ae39bba..65b9956 100644
--- a/crypt.go
+++ b/crypt.go
@@ -43,6 +43,7 @@ var (
packageOffset = 8 // First 8 bytes are the size of the stream
packageEncryptionChunkSize = 4096
iterCount = 50000
+ sheetProtectionSpinCount = 1e5
oleIdentifier = []byte{
0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1,
}
@@ -146,7 +147,7 @@ func Decrypt(raw []byte, opt *Options) (packageBuf []byte, err error) {
case "standard":
return standardDecrypt(encryptionInfoBuf, encryptedPackageBuf, opt)
default:
- err = ErrUnsupportEncryptMechanism
+ err = ErrUnsupportedEncryptMechanism
}
return
}
@@ -307,7 +308,7 @@ func encryptionMechanism(buffer []byte) (mechanism string, err error) {
} else if (versionMajor == 3 || versionMajor == 4) && versionMinor == 3 {
mechanism = "extensible"
}
- err = ErrUnsupportEncryptMechanism
+ err = ErrUnsupportedEncryptMechanism
return
}
@@ -387,14 +388,14 @@ func standardConvertPasswdToKey(header StandardEncryptionHeader, verifier Standa
key = hashing("sha1", iterator, key)
}
var block int
- hfinal := hashing("sha1", key, createUInt32LEBuffer(block, 4))
+ hFinal := hashing("sha1", key, createUInt32LEBuffer(block, 4))
cbRequiredKeyLength := int(header.KeySize) / 8
cbHash := sha1.Size
buf1 := bytes.Repeat([]byte{0x36}, 64)
- buf1 = append(standardXORBytes(hfinal, buf1[:cbHash]), buf1[cbHash:]...)
+ buf1 = append(standardXORBytes(hFinal, buf1[:cbHash]), buf1[cbHash:]...)
x1 := hashing("sha1", buf1)
buf2 := bytes.Repeat([]byte{0x5c}, 64)
- buf2 = append(standardXORBytes(hfinal, buf2[:cbHash]), buf2[cbHash:]...)
+ buf2 = append(standardXORBytes(hFinal, buf2[:cbHash]), buf2[cbHash:]...)
x2 := hashing("sha1", buf2)
x3 := append(x1, x2...)
keyDerived := x3[:cbRequiredKeyLength]
@@ -417,7 +418,8 @@ func standardXORBytes(a, b []byte) []byte {
// ECMA-376 Agile Encryption
// agileDecrypt decrypt the CFB file format with ECMA-376 agile encryption.
-// Support cryptographic algorithm: MD4, MD5, RIPEMD-160, SHA1, SHA256, SHA384 and SHA512.
+// Support cryptographic algorithm: MD4, MD5, RIPEMD-160, SHA1, SHA256,
+// SHA384 and SHA512.
func agileDecrypt(encryptionInfoBuf, encryptedPackageBuf []byte, opt *Options) (packageBuf []byte, err error) {
var encryptionInfo Encryption
if encryptionInfo, err = parseEncryptionInfo(encryptionInfoBuf[8:]); err != nil {
@@ -605,11 +607,55 @@ func createIV(blockKey interface{}, encryption Encryption) ([]byte, error) {
return iv, nil
}
-// randomBytes returns securely generated random bytes. It will return an error if the system's
-// secure random number generator fails to function correctly, in which case the caller should not
-// continue.
+// randomBytes returns securely generated random bytes. It will return an
+// error if the system's secure random number generator fails to function
+// correctly, in which case the caller should not continue.
func randomBytes(n int) ([]byte, error) {
b := make([]byte, n)
_, err := rand.Read(b)
return b, err
}
+
+// ISO Write Protection Method
+
+// genISOPasswdHash implements the ISO password hashing algorithm by given
+// plaintext password, name of the cryptographic hash algorithm, salt value
+// and spin count.
+func genISOPasswdHash(passwd, hashAlgorithm, salt string, spinCount int) (hashValue, saltValue string, err error) {
+ if len(passwd) < 1 || len(passwd) > MaxFieldLength {
+ err = ErrPasswordLengthInvalid
+ return
+ }
+ hash, ok := map[string]string{
+ "MD4": "md4",
+ "MD5": "md5",
+ "SHA-1": "sha1",
+ "SHA-256": "sha256",
+ "SHA-384": "sha384",
+ "SHA-512": "sha512",
+ }[hashAlgorithm]
+ if !ok {
+ err = ErrUnsupportedHashAlgorithm
+ return
+ }
+ var b bytes.Buffer
+ s, _ := randomBytes(16)
+ if salt != "" {
+ if s, err = base64.StdEncoding.DecodeString(salt); err != nil {
+ return
+ }
+ }
+ b.Write(s)
+ encoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
+ passwordBuffer, _ := encoder.Bytes([]byte(passwd))
+ b.Write(passwordBuffer)
+ // Generate the initial hash.
+ key := hashing(hash, b.Bytes())
+ // Now regenerate until spin count.
+ for i := 0; i < spinCount; i++ {
+ iterator := createUInt32LEBuffer(i, 4)
+ key = hashing(hash, key, iterator)
+ }
+ hashValue, saltValue = base64.StdEncoding.EncodeToString(key), base64.StdEncoding.EncodeToString(s)
+ return
+}