Module: Kindle::DRM

Defined in:
lib/kindle/drm.rb

Constant Summary collapse

LETTERS =
"ABCDEFGHIJKLMNPQRSTUVWXYZ123456789".split(//)

Instance Method Summary collapse

Instance Method Details

#checksumPid(s) ⇒ Object

Generates the actual Personal ID (PID) needed to tie/untie content (such as .mobi/.azw files) to a specific device.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/kindle/drm.rb', line 16

def checksumPid(s)
	tmp = crc32(s)
	crc = tmp ^ (tmp >> 16)
	res = s
	l = LETTERS.length
	for i in 0..1 do
		b = crc & 0xFF
		t = b.divmod(l)[0]
		pos = t ^ (b % l)
		res = "#{res}#{LETTERS[pos % l]}"
		crc >>= 8
	end
	res
end

#crc32(s) ⇒ Object

Special cyclical redundancy check (checksumming) function.



10
11
12
# File 'lib/kindle/drm.rb', line 10

def crc32(s)
	(~Zlib.crc32(s, -1)) & 0xFFFFFFFF
end

#serialToDeviceTypeAndPidSize(serial) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/kindle/drm.rb', line 58

def serialToDeviceTypeAndPidSize(serial)
	type = nil
	size = nil
	pad = nil
	
	l = serial.length
	if l == 16
		case serial[0, 4]
		when /^B001/
			type = "Kindle 1"
		when /^B101/
			type = "Kindle 1"
		when /^B002/
			type = "Kindle 2"
		when /^B003/
			type = "Kindle 2 International"
		when /^B004/
			type = "Kindle DX"
		when /^B005/
			type = "Kindle DX 2"
		when /^B009/
			type = "Kindle DX International 2 (Graphite)"
		when /^B/
			type = "Unknown Kindle model. Please report!"
		end
		size = 7
		pad = '*'
	elsif l == 40
		type = "iPhone"
		size = 8
	end

	return nil if type.nil? || size.nil?
	return [type, size, pad]
end

#serialToIntermediaryPid(s, l) ⇒ Object

Figures out the intermediary Personal ID (PID) of a device based on its serial number and expected length of the output. Apparently this varies by the type of device.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/kindle/drm.rb', line 34

def serialToIntermediaryPid(s, l)
	crc = crc32(s)  
	arr1 = Array.new(l, 0)
	for i in 0..(s.length - 1) do
		code = s[i]
		code = code.ord if code.class == String # Fix for Ruby 1.9+
		arr1[i%l] ^= code
	end

	# Grab each CRC byte and OR with a portion of the 
	crc_bytes = [crc >> 24 & 0xff, crc >> 16 & 0xff, crc >> 8 & 0xff, crc & 0xff]
	for i in 0..(l - 1) do
		arr1[i] ^= crc_bytes[i&3]
	end

	pid = ""
	for i in 0..(l-1) do
		b = arr1[i] & 0xff
		pid += LETTERS[(b >> 7) + ((b >> 5 & 3) ^ (b & 0x1f))]
	end
	pid
end

#serialToPid(serial) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/kindle/drm.rb', line 95

def serialToPid(serial)
	pid = nil
	type, size, pad = serialToDeviceTypeAndPidSize(serial)
	if type.nil?
		# No dice.. :(
	else
		ipid = serialToIntermediaryPid(serial, size)
		ipid += pad unless pad.nil?
		pid = checksumPid(ipid)
	end
	pid
end