본문 바로가기
2014.12.03 05:38

Byte manipulation in Ruby

조회 수 1434 추천 수 0 댓글 0
?

단축키

Prev이전 문서

Next다음 문서

+ - Up Down Comment Print
?

단축키

Prev이전 문서

Next다음 문서

+ - Up Down Comment Print

http://www.happybearsoftware.com/byte-manipulation-in-ruby.html

Integers with different bases

Literals

It can be useful to to be able to type integer literals in different bases in your code:

97         #=> 97 in decimal (base 10)
0x61       #=> 97 in hex     (base 16)
0141       #=> 97 in octal   (base 8)
0b01100001 #=> 97 in binary  (base 2)

# These are all just different ways of typing the same thing:
[0141, 0x61, 0b01100001, 97] #=> [97, 97, 97, 97]

Representation at different bases

Ints take a parameter in to_s for the base:

97.to_s(10) #=> '97'      (base 10)
97.to_s(16) #=> '61'      (base 16)
97.to_s(8)  #=> '141'     (base 8)
97.to_s(2)  #=> '1100001' (base 2)

Strings/bytes

For a given character, can switch back and forth between chars/bytes with chr and ord:

97.chr  #=> 'a'
'a'.ord #=> 97

# For strings of length > 1, ord returns the integer representation 
# of the first char:
'abc'.ord #=> 97

You can get the bytes out of a string with .bytes:

"Hello, world".bytes
# => [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100]

Note that since ruby is unicode aware, this is not the same as .chars.map(&:ord).

Array#pack and String#unpack

Array#pack is a method for 'packing' an array into a string of bytes according to a certain format. Some examples:

hw_bytes = "Hello, world".bytes
# => [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100]

# c* => Pack every element as an 8 bit signed integer
# As a string, this is exactly the same as "Hello, world"
hw_bytes.pack('c*') # => "Hello, world"

# s5 => Pack the first five elements as 16 bit signed integers
# Since "Hello".bytes is a bunch of 8-bit integers, the string contains 
# a null byte after every 8-bit char
hw_bytes.pack('s5') # => "H\0e\0l\0l\0o\0"

# There's also an 'm' format that we can use for fast base64 encoding:
["Hello, world"].pack('m0') #=> "SGVsbG8sIHdvcmxk"

String#unpack takes you in the other direction: it lets you take a string in a certain binary format and 'unpack' it into an array:

# This says: read the string as a sequence 8-bit integers and 
# put each of those integers into an array
"Hello, world".unpack('c*')
# => [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100]

# Read as a sequence of 16 bit integers and put each
# of those 16 bit integers into an array (gets us hw_bytes)
"H\0e\0l\0l\0o\0,\0 \0w\0o\0r\0l\0d\0".unpack('s*')
# => [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100]

# As with Array#pack, we can use the 'm' format and base64 decode
"SGVsbG8sIHdvcmxk".unpack('m0') # => ["Hello, world"]

XORing bits

XOR is a reversible way to 'mix' data together, and is the bread and butter operation of modern cryptography. At the logic level it means one or the other but not both and so for bits the truth table looks like this:

10
101
010

Like a lot of languages, in ruby the ^ operator denotes XOR. An example XOR with base 2 literals:

# The key insight with XORing bits is that in the result, all bits that 
# are *different* are 1, and all bits that are the *same* are 0
0b1110 ^ 0b1101
# => 0b0011

Combining some of the other tools together, we can put together a short method to xor the bytes of two strings together and return the resulting byte string:

class String
  def xor_with(other_string)
    self.bytes.zip(other_string.bytes).map { |(a,b)| a ^ b }.pack('c*')
  end
end

# This gets us random junk
"Hello".xor_with('world')
# => "?\n\x1E\0\v"

# A strings bytes XOR'd with its self should be a string of null bytes:
"Hello".xor_with("Hello")
# => "\0\0\0\0\0"

# This is useful for when you want to compare two strings for equality 
# in a time-insensitive way (i.e. to mitigate timing attacks)

Title
List of Articles
번호 제목 글쓴이 날짜 조회 수
31 Different Ways to Set Attributes in ActiveRecord (attribute, create, update, validation) Hojung 2015.05.24 1268
30 Ruby Style Guide Hojung 2015.02.05 1605
29 Refresh content automatically after some period time on Rails Hojung 2015.01.22 2210
28 Install ruby-filemagic on Mac (brew, libmagic) Hojung 2014.12.03 1475
» Byte manipulation in Ruby Hojung 2014.12.03 1434
26 How to use Github for your project file Hojung 2014.09.24 1051
25 Ruby map, each, collect, inject, reject, select quick reference Hojung 2014.06.10 1814
24 Difference between collect, select, map and each in ruby Hojung 2014.06.10 1296
23 remove nil from array (compact, compact!) Hojung 2014.06.10 1603
22 remove child association model when parent removed (rails-dependent-destroy) Hojung 2014.06.03 1661
21 deploying cron jobs with whenever gem Hojung 2014.06.01 1702
20 Get list of a class' instance methods Hojung 2014.06.01 1364
19 Optional method parameters in Ruby Hojung 2014.05.29 1486
18 Best Ruby On Rails Content Management Systems (CMS) Hojung 2014.04.26 2682
17 The simple way to print exceptions in Ruby Hojung 2014.04.07 1516
16 Ruby Symbols Hojung 2014.04.05 6290
15 What is the difference between a Symbol and String? Hojung 2014.04.05 1493
14 install Rbenv, ruby and rails Hojung 2014.03.22 1669
13 HTTP Posts in Ruby Hojung 2014.03.14 1664
12 optparse: mandatory and optional arguments example Hojung 2014.03.14 2351
Board Pagination ‹ Prev 1 2 Next ›
/ 2

Designed by sketchbooks.co.kr / sketchbook5 board skin

나눔글꼴 설치 안내


이 PC에는 나눔글꼴이 설치되어 있지 않습니다.

이 사이트를 나눔글꼴로 보기 위해서는
나눔글꼴을 설치해야 합니다.

설치 취소

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5

Sketchbook5, 스케치북5