7

Note: I found a similar question, but it is in python.


I've been trying to think of an algorithm or native method for this, and I'm stumped.

This is what I have so far:

encode=function(n,f){
    return (n).toString(f)
}
decode=function(s,f){
    return parseInt(s,f)
}

Basically, I need a way to convert a string, like 'Hello World!' to a base 10 (hexadecimal will work as well) number, like 14438792758793754875, and I am wondering if there's a proper way to do it before I possibly waste my time with something like:

str='Hello World'
returnString=''
for(var i in str){
    returnString+=(
        str[i]=='A'?'0'
        :str[i]=='B'?'1'
        etc...
    )
}

Not only would that be very time consuming, but I have no idea how I would possibly convert it back, as once I get into numbers like 11 for L, a for loop wouldn't do, and would return BB.

The reason I am asking this is because I plan to use it in the future for more efficient and secure, encrypted storage. for example, something like:

//save
numstr=encodeToNumber(inputElement.value)
b36str=encode(numstr,36)
storage['items'].push(b36str)
localStorage['App Data']=JSON.stringify(storage)

//load
if(localStorage['App Data']){
    storage=JSON.parse(localStorage['App Data'])
}else{
    storage={
        items:[],
        config:{
            etc
        }
    }
}
//Assuming storage.items looks like this: ['rgie', 'zyy', '2il7']
for(i in storage['items']){
    b36str=storage['items']//rgie, zyy, 2il7
    numstr=decode(b36str,36)//1281110, 46618, 117403
    container.innerHTML+='<hr>'+decodeFromNumber(numstr)//Milk, Eggs, Bread
}

//Output
Milk
Eggs
Bread

I actually did spend several minutes manually encrypting 'Milk', 'Eggs', and 'Bread' to their base36 counterparts so it could be accurate.


Update: Aadit M Shaw gave a function that produces hexadecimal strings from strings, and I reverse engineered it to my needs and got this:

en=function(s){
    var s2d=function(s){
        s=s.replace(/ /g,'+').replace(/!/g,'.')
        var n=[]
        for(var i in s){
            n.push(s.charCodeAt(i))
        }
        return n
    }
    var arr=s2d(s)
    var s2=''
    for (var i in arr){
        s2+=arr[i].toString(36)
    }
    return s2
}
de=function(s){
    var arr=s.split(/(..)/)
    var arr2=[]
    var s2=''
    for(var i in arr){
        if(arr[i]){
            arr2.push(parseInt(arr[i],36))
        }
    }
    for(var i in arr2){
        s2+=String.fromCharCode(arr2[i])
    }
    return s2.replace(/\+/g,' ')
}

While the encoded string is larger than I would have liked, it could be useful for protecting cookies from being hacked or something.

For example, using the example I made here, I made this message 21173b2x3030172t2p38173d333936172u2p2r2t as well as this ЎDŽ̺ǦDŽ̌. And if you manage to decode the second one, then decode this too ʒ̴ͻϮ

This isn't very practical, though, so I'll probably end up using the library Ragnarokkr linked me to.

Thank you all for the responses!

Community
  • 1
  • 1
Braden Best
  • 8,830
  • 3
  • 31
  • 43
  • Define "encrypted": Why not just encrypt it? – Dave Newton Jan 15 '13 at 21:04
  • @Dave I'm not sure I understand your question. If you're asking why I don't just use the `encode` method I provided, it's because it only accepts base 10 integers. – Braden Best Jan 15 '13 at 21:05
  • 3
    If you want something secure, something trivial like this is useless. I'm asking why don't you just use actual encryption instead of trying to implement something yourself? I don't understand your comment regarding "base 10 integers", you said it could be hex--which is it? – Dave Newton Jan 15 '13 at 21:07
  • 1
    if you need **true** encryption, I think [this library](http://code.google.com/p/crypto-js/) could be really useful. It supports hash and encryption/decryption algorithms as well. – Ragnarokkr Jan 15 '13 at 21:07
  • @DaveNewton because I haven't found any native method, and I'm trying to do this with only JavaScript. And I accept hexadecimal because I could easily just decode that to decimal and the re encode to base 36 – Braden Best Jan 15 '13 at 21:08
  • @Ragnarokkr I'll definitely give that a look – Braden Best Jan 15 '13 at 21:10
  • @B1KMusic There isn't native encryption, but there are many encryption libraries. – Dave Newton Jan 15 '13 at 21:11
  • If the concern is data traveling through the internet, there is a well known way to encrypt things. It is called ssl/tls. You can send data through it just like with http, but it will get encrypted before it is sent. Most people call it https. – Patrick James McDougle Jan 15 '13 at 21:13
  • @Dave I'm fine with using a library. – Braden Best Jan 15 '13 at 21:16
  • I guess, http://code.google.com/p/crypto-js/ is what you need. It is easy-to-use and it contains several algorithms. So, for you algorithm AES or converting input string to hex string can be appropriate – Igor Jan 15 '13 at 21:18
  • @Patrick Yes I am fond of Transport Layer Security, but my main purpose for this is the design of webapps which use localStorage. Since localStorage has that 5 MB limit, base 36 encoding could increase the amount of data that can be saved. This was my initial reason for experimenting with this. – Braden Best Jan 15 '13 at 21:20
  • @Ragnarokkr If you had answered with that link I would have given you the `accepted answer`. Thanks alot! It's a great library. – Braden Best Jan 15 '13 at 23:18
  • 1
    @B1KMusic thanks. I'm happy to know that it was helpful to you ;) – Ragnarokkr Jan 15 '13 at 23:35

2 Answers2

9

Try this:

function encode(string) {
    var number = "0x";
    var length = string.length;
    for (var i = 0; i < length; i++)
        number += string.charCodeAt(i).toString(16);
    return number;
}

See the demo here: http://jsfiddle.net/hGKAg/2/

Decoding is just as simple:

function decode(number) {
    var string = "";
    number = number.slice(2);
    var length = number.length;
    for (var i = 0; i < length;) {
        var code = number.slice(i, i += 2);
        string += String.fromCharCode(parseInt(code, 16));
    }
    return string;
}

Try the demo: http://jsfiddle.net/hGKAg/3/

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • I can't really use `8.752161808888254e+25` (what I got from entering `Hello World`) – Braden Best Jan 15 '13 at 21:12
  • @B1KMusic - I updated the answer. Since you don't mind hexadecimal, this should solve your problem. – Aadit M Shah Jan 15 '13 at 21:17
  • Umm, I still got `8.752161808888254e+25` when I converted the hex string back to decimal. – Braden Best Jan 15 '13 at 21:23
  • @B1KMusic - The problem is that JavaScript numbers are double precision floating point values. That's why very large values get converted to exponential form. – Aadit M Shah Jan 15 '13 at 21:26
  • @B1KMusic - Is it essential for you to convert the string into a number? If not then IMHO this is all you need. – Aadit M Shah Jan 15 '13 at 21:30
  • Oh, silly me. I __can__ use this, because when I tried to convert the number to base 36 I got `azw5bz2xp57qck4sw`. But when I decoded it back I got "ello X". So there's still a problem... – Braden Best Jan 15 '13 at 21:32
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/22783/discussion-between-b1kmusic-and-aadit-m-shah) – Braden Best Jan 15 '13 at 21:33
  • 1
    From the method you used, `String.prototype.charCodeAt()`, I was able to engineer my own method, and successfully translated `Hello` to `202t303033` and back. So I'm upvoting your answer. Thanks – Braden Best Jan 15 '13 at 22:02
  • This is a good answer, but the base here is `16`. The OP questions was for a base 10. – Holger Ludvigsen Jan 10 '23 at 15:15
  • @HolgerLudvigsen The OP mentioned in his question that _“hexadecimal will work as well”_. – Aadit M Shah Jan 11 '23 at 06:01
1

While I've never used this before, a friend of mine has given this library a good review. Apparently, you can encode strings using any Base standard with this library:

Nibbler.js

kinsho
  • 516
  • 3
  • 11