Skip to content

Commit 3c6b32e

Browse files
committed
Implement decipher stub for epub font obfuscation algorithm
1 parent 599353e commit 3c6b32e

File tree

1 file changed

+43
-10
lines changed

1 file changed

+43
-10
lines changed

pkg/lcp/lcp.go

+43-10
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ func WithLogger(log func(msg string)) DecryptOption {
2828
}
2929
}
3030

31+
type EncryptionAlgorithm string
32+
33+
const (
34+
EncryptionAlgorithmAES256CBC EncryptionAlgorithm = "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
35+
EncryptionAlgorithmFontObfuscation EncryptionAlgorithm = "http://www.idpf.org/2008/embedding"
36+
)
37+
3138
// Decrypt reads an EPUB file encrypted with the Readium LCP DRM from in and
3239
// outputs a regular EPUB file to out.
3340
//
@@ -113,7 +120,7 @@ func Decrypt(out io.Writer, in io.ReaderAt, inSize int64, userKeyHex string, opt
113120
}
114121

115122
if fileEntry, ok := encryptedFilesSet[f.Name]; ok {
116-
err = decryptFile(dstFile, srcFile, contentKey, fileEntry.IsCompressed)
123+
err = decryptFile(dstFile, srcFile, contentKey, fileEntry.EncryptionAlgorithm, fileEntry.IsCompressed)
117124
} else {
118125
_, err = io.Copy(dstFile, srcFile)
119126
}
@@ -137,8 +144,9 @@ func Decrypt(out io.Writer, in io.ReaderAt, inSize int64, userKeyHex string, opt
137144
}
138145

139146
type FileEntry struct {
140-
Path string
141-
IsCompressed bool
147+
Path string
148+
IsCompressed bool
149+
EncryptionAlgorithm EncryptionAlgorithm
142150
}
143151

144152
func listEncryptedFiles(epubRoot fs.FS) ([]FileEntry, error) {
@@ -178,8 +186,12 @@ func listEncryptedFiles(epubRoot fs.FS) ([]FileEntry, error) {
178186
for _, d := range encryption.EncryptedData {
179187
path := d.CipherData.CipherReference.URI
180188
isCompressed := false
189+
var encryptionAlgorithm EncryptionAlgorithm
181190

182-
if d.EncryptionMethod.Algorithm != "http://www.w3.org/2001/04/xmlenc#aes256-cbc" {
191+
switch d.EncryptionMethod.Algorithm {
192+
case string(EncryptionAlgorithmAES256CBC), string(EncryptionAlgorithmFontObfuscation):
193+
encryptionAlgorithm = EncryptionAlgorithm(d.EncryptionMethod.Algorithm)
194+
default:
183195
return nil, fmt.Errorf("unsupported encryption algorithm for file %s: %s", path, d.EncryptionMethod.Algorithm)
184196
}
185197

@@ -193,7 +205,11 @@ func listEncryptedFiles(epubRoot fs.FS) ([]FileEntry, error) {
193205
}
194206
}
195207

196-
res = append(res, FileEntry{Path: path, IsCompressed: isCompressed})
208+
res = append(res, FileEntry{
209+
Path: path,
210+
IsCompressed: isCompressed,
211+
EncryptionAlgorithm: encryptionAlgorithm,
212+
})
197213
}
198214

199215
return res, nil
@@ -236,7 +252,7 @@ func getContentKey(epubRoot fs.FS, userKey []byte) ([]byte, error) {
236252
return nil, fmt.Errorf("error decoding key check: %w", err)
237253
}
238254

239-
keyCheck, err := decipher(encryptedKeyCheck, userKey)
255+
keyCheck, err := decipherAES256CBC(encryptedKeyCheck, userKey)
240256
if err != nil {
241257
return nil, fmt.Errorf("error decrypting key check: %w", err)
242258
}
@@ -250,15 +266,15 @@ func getContentKey(epubRoot fs.FS, userKey []byte) ([]byte, error) {
250266
return nil, fmt.Errorf("error decoding content key: %w", err)
251267
}
252268

253-
contentKey, err := decipher(encryptedContentKey, userKey)
269+
contentKey, err := decipherAES256CBC(encryptedContentKey, userKey)
254270
if err != nil {
255271
return nil, fmt.Errorf("error decrypting content key: %w", err)
256272
}
257273

258274
return contentKey, nil
259275
}
260276

261-
func decipher(data, key []byte) ([]byte, error) {
277+
func decipherAES256CBC(data, key []byte) ([]byte, error) {
262278
block, err := aes.NewCipher(key)
263279
if err != nil {
264280
return nil, fmt.Errorf("error creating cipher: %w", err)
@@ -283,13 +299,30 @@ func decipher(data, key []byte) ([]byte, error) {
283299
return res, nil
284300
}
285301

286-
func decryptFile(dst io.Writer, src io.Reader, contentKey []byte, isCompressed bool) error {
302+
func decipherFontObfuscation(data, key []byte) ([]byte, error) {
303+
// Let's assume readers know how to deal with this algorithm... Worst case,
304+
// let's hope they fallback to any font.
305+
return data, nil
306+
}
307+
308+
func decryptFile(dst io.Writer, src io.Reader, contentKey []byte, encryptionAlgorithm EncryptionAlgorithm, isCompressed bool) error {
287309
encryptedData, err := io.ReadAll(src)
288310
if err != nil {
289311
return fmt.Errorf("error reading data: %w", err)
290312
}
291313

292-
data, err := decipher(encryptedData, contentKey)
314+
var decipherFunc func(data []byte, key []byte) (res []byte, err error)
315+
316+
switch encryptionAlgorithm {
317+
case EncryptionAlgorithmAES256CBC:
318+
decipherFunc = decipherAES256CBC
319+
case EncryptionAlgorithmFontObfuscation:
320+
decipherFunc = decipherFontObfuscation
321+
default:
322+
return fmt.Errorf("invalid encryption algorithm: %s", encryptionAlgorithm)
323+
}
324+
325+
data, err := decipherFunc(encryptedData, contentKey)
293326
if err != nil {
294327
return fmt.Errorf("error decrypting data: %w", err)
295328
}

0 commit comments

Comments
 (0)